QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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()->dataSourceUri() )
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  // plugin layers do not have a standard way of storing their URI...
97  return;
98  }
99  }
100 }
101 
103 {
104  return encode( QStringList() << layerType << providerKey << name << uri << encode( supportedCrs ) << encode( supportedFormats ) << layerId << pId << QgsWkbTypes::displayString( wkbType ) );
105 }
106 
107 QgsVectorLayer *QgsMimeDataUtils::Uri::vectorLayer( bool &owner, QString &error ) const
108 {
109  owner = false;
110  error.clear();
111  if ( layerType != QLatin1String( "vector" ) )
112  {
113  error = QObject::tr( "%1: Not a vector layer." ).arg( name );
114  return nullptr;
115  }
116 
118  {
120  {
121  return vectorLayer;
122  }
123  }
124  if ( providerKey == QLatin1String( "memory" ) )
125  {
126  error = QObject::tr( "Cannot get memory layer." );
127  return nullptr;
128  }
129 
130  owner = true;
132  return new QgsVectorLayer( uri, name, providerKey, options );
133 }
134 
135 QgsRasterLayer *QgsMimeDataUtils::Uri::rasterLayer( bool &owner, QString &error ) const
136 {
137  owner = false;
138  error.clear();
139  if ( layerType != QLatin1String( "raster" ) )
140  {
141  error = QObject::tr( "%1: Not a raster layer." ).arg( name );
142  return nullptr;
143  }
144 
146  {
148  {
149  return rasterLayer;
150  }
151  }
152 
153  owner = true;
154  return new QgsRasterLayer( uri, name, providerKey );
155 }
156 
157 QgsMeshLayer *QgsMimeDataUtils::Uri::meshLayer( bool &owner, QString &error ) const
158 {
159  owner = false;
160  error.clear();
161  if ( layerType != QLatin1String( "mesh" ) )
162  {
163  error = QObject::tr( "%1: Not a mesh layer." ).arg( name );
164  return nullptr;
165  }
166 
168  {
170  {
171  return meshLayer;
172  }
173  }
174 
175  owner = true;
176  return new QgsMeshLayer( uri, name, providerKey );
177 }
178 
180 {
182  {
184  }
185  return nullptr;
186 }
187 
188 // -----
189 
190 bool QgsMimeDataUtils::isUriList( const QMimeData *data )
191 {
192  return data->hasFormat( QGIS_URILIST_MIMETYPE );
193 }
194 
196 {
197  QMimeData *mimeData = new QMimeData();
198 
199  mimeData->setData( QGIS_URILIST_MIMETYPE, uriListToByteArray( layers ) );
200  return mimeData;
201 }
202 
203 
205 {
206  QByteArray encodedData = data->data( QGIS_URILIST_MIMETYPE );
207  QDataStream stream( &encodedData, QIODevice::ReadOnly );
208  QString xUri; // extended uri: layer_type:provider_key:uri
209  UriList list;
210  while ( !stream.atEnd() )
211  {
212  stream >> xUri;
213  QgsDebugMsgLevel( xUri, 4 );
214  list.append( Uri( xUri ) );
215  }
216  return list;
217 }
218 
219 
220 static void _addLayerTreeNodeToUriList( QgsLayerTreeNode *node, QgsMimeDataUtils::UriList &uris )
221 {
222  if ( QgsLayerTree::isGroup( node ) )
223  {
224  const auto constChildren = QgsLayerTree::toGroup( node )->children();
225  for ( QgsLayerTreeNode *child : constChildren )
226  _addLayerTreeNodeToUriList( child, uris );
227  }
228  else if ( QgsLayerTree::isLayer( node ) )
229  {
230  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
231  QgsMapLayer *layer = nodeLayer->layer();
232  if ( !layer )
233  return;
234 
235  if ( layer->type() == QgsMapLayerType::PluginLayer )
236  return; // plugin layers do not have a standard way of storing their URI...
237 
238  uris << QgsMimeDataUtils::Uri( layer );
239  }
240 }
241 
242 QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *> &nodes )
243 {
244  UriList uris;
245  const auto constNodes = nodes;
246  for ( QgsLayerTreeNode *node : constNodes )
247  _addLayerTreeNodeToUriList( node, uris );
248  return uriListToByteArray( uris );
249 }
250 
252 {
253  if ( uri.pId.isEmpty() )
254  return false;
255 
256  const qint64 pid = uri.pId.toLongLong();
257  return pid == QCoreApplication::applicationPid();
258 }
259 
260 QString QgsMimeDataUtils::encode( const QStringList &items )
261 {
262  QString encoded;
263  // Do not escape colon twice
264  QRegularExpression re( QStringLiteral( "(?<!\\\\):" ) );
265  const auto constItems = items;
266  for ( const QString &item : constItems )
267  {
268  QString str = item;
269  str.replace( '\\', QStringLiteral( "\\\\" ) );
270  str.replace( re, QStringLiteral( "\\:" ) );
271  encoded += str + ':';
272  }
273  return encoded.left( encoded.length() - 1 );
274 }
275 
276 QStringList QgsMimeDataUtils::decode( const QString &encoded )
277 {
278  QStringList items;
279  QString item;
280  bool inEscape = false;
281  const auto constEncoded = encoded;
282  for ( QChar c : constEncoded )
283  {
284  if ( c == '\\' && inEscape )
285  {
286  item += c;
287  }
288  else if ( c == '\\' )
289  {
290  inEscape = true;
291  }
292  else if ( c == ':' && !inEscape )
293  {
294  items.append( item );
295  item.clear();
296  }
297  else
298  {
299  item += c;
300  inEscape = false;
301  }
302  }
303  items.append( item );
304  return items;
305 }
306 
307 
308 QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList &layers )
309 {
310  QByteArray encodedData;
311 
312  QDataStream stream( &encodedData, QIODevice::WriteOnly );
313  const auto constLayers = layers;
314  for ( const Uri &u : constLayers )
315  {
316  stream << u.data();
317  }
318  return encodedData;
319 }
QString layerType
Type of URI.
static bool hasOriginatedFromCurrentAppInstance(const QgsMimeDataUtils::Uri &uri)
Returns true if uri originated from the current QGIS application instance.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
Base class for all map layer types.
Definition: qgsmaplayer.h:79
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
QgsMapLayerType type() const
Returns the type of the layer.
Setting options for loading vector layers.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
static UriList decodeUriList(const QMimeData *data)
QString name
Human readable name to be used e.g. in layer tree.
static QMimeData * encodeUriList(const UriList &layers)
Encodes a URI list to a new QMimeData object.
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
static bool isUriList(const QMimeData *data)
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
QgsMapLayer * mapLayer() const
Returns the layer from the active project corresponding to this uri (if possible), otherwise returns nullptr.
QString data() const
Returns encoded representation of the object.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
This class is a base class for nodes in a layer tree.
QgsVectorLayer * vectorLayer(bool &owner, QString &error) const
Gets vector layer from uri if possible, otherwise returns nullptr and error is set.
Uri()=default
Constructs invalid URI.
QgsMeshLayer * meshLayer(bool &owner, QString &error) const
Gets mesh layer from uri if possible, otherwise returns nullptr and error is set. ...
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:96
QgsMapLayer * layer() const
Returns the map layer associated with this node.
QString pId
Unique ID associated with application instance.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:442
QList< QgsMimeDataUtils::Uri > UriList
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
QString providerKey
For "vector" / "raster" type: provider id.
QString layerId
Layer ID, if uri is associated with a layer from a QgsProject.
QString uri
Identifier of the data source recognized by its providerKey.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:90
static QByteArray layerTreeNodesToUriList(const QList< QgsLayerTreeNode *> &nodes)
Returns encoded URI list from a list of layer tree nodes.
QgsRasterLayer * rasterLayer(bool &owner, QString &error) const
Gets raster layer from uri if possible, otherwise returns nullptr and error is set.
QgsWkbTypes::Type wkbType
WKB type, if associated with a vector layer, or QgsWkbTypes::Unknown if not yet known.
Represents a vector layer which manages a vector based data sets.
Layer tree node points to a map layer.