QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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( QString &encData )
32 {
33  QgsDebugMsg( "encData: " + encData );
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->dataProvider()->name() )
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  QgsDebugMsg( xUri );
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:78
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.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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:438
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.
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.