QGIS API Documentation  3.6.0-Noosa (5873452)
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  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  QgsDebugMsg( QStringLiteral( "type:%1 key:%2 name:%3 uri:%4 supportedCRS:%5 supportedFormats:%6" )
55  .arg( layerType, providerKey, name, uri,
56  supportedCrs.join( ", " ),
57  supportedFormats.join( ", " ) ) );
58 }
59 
61 {
62  return encode( QStringList() << layerType << providerKey << name << uri << encode( supportedCrs ) << encode( supportedFormats ) );
63 }
64 
65 QgsVectorLayer *QgsMimeDataUtils::Uri::vectorLayer( bool &owner, QString &error ) const
66 {
67  owner = false;
68  if ( layerType != QLatin1String( "vector" ) )
69  {
70  error = QObject::tr( "%1: Not a vector layer." ).arg( name );
71  return nullptr;
72  }
73  if ( providerKey == QLatin1String( "memory" ) )
74  {
75  QUrl url = QUrl::fromEncoded( uri.toUtf8() );
76  if ( !url.hasQueryItem( QStringLiteral( "pid" ) ) || !url.hasQueryItem( QStringLiteral( "layerid" ) ) )
77  {
78  error = QObject::tr( "Memory layer uri does not contain process or layer id." );
79  return nullptr;
80  }
81  qint64 pid = url.queryItemValue( QStringLiteral( "pid" ) ).toLongLong();
82  if ( pid != QCoreApplication::applicationPid() )
83  {
84  error = QObject::tr( "Memory layer from another QGIS instance." );
85  return nullptr;
86  }
87  QString layerId = url.queryItemValue( QStringLiteral( "layerid" ) );
89  if ( !vectorLayer )
90  {
91  error = QObject::tr( "Cannot get memory layer." );
92  return nullptr;
93  }
94  return vectorLayer;
95  }
96  owner = true;
97  return new QgsVectorLayer( uri, name, providerKey );
98 }
99 
100 QgsRasterLayer *QgsMimeDataUtils::Uri::rasterLayer( bool &owner, QString &error ) const
101 {
102  owner = false;
103  if ( layerType != QLatin1String( "raster" ) )
104  {
105  error = QObject::tr( "%1: Not a raster layer." ).arg( name );
106  return nullptr;
107  }
108  owner = true;
109  return new QgsRasterLayer( uri, name, providerKey );
110 }
111 
112 QgsMeshLayer *QgsMimeDataUtils::Uri::meshLayer( bool &owner, QString &error ) const
113 {
114  owner = false;
115  if ( layerType != QLatin1String( "mesh" ) )
116  {
117  error = QObject::tr( "%1: Not a mesh layer." ).arg( name );
118  return nullptr;
119  }
120  owner = true;
121  return new QgsMeshLayer( uri, name, providerKey );
122 }
123 
124 // -----
125 
126 bool QgsMimeDataUtils::isUriList( const QMimeData *data )
127 {
128  return data->hasFormat( QGIS_URILIST_MIMETYPE );
129 }
130 
132 {
133  QMimeData *mimeData = new QMimeData();
134 
135  mimeData->setData( QGIS_URILIST_MIMETYPE, uriListToByteArray( layers ) );
136  return mimeData;
137 }
138 
139 
141 {
142  QByteArray encodedData = data->data( QGIS_URILIST_MIMETYPE );
143  QDataStream stream( &encodedData, QIODevice::ReadOnly );
144  QString xUri; // extended uri: layer_type:provider_key:uri
145  UriList list;
146  while ( !stream.atEnd() )
147  {
148  stream >> xUri;
149  QgsDebugMsg( xUri );
150  list.append( Uri( xUri ) );
151  }
152  return list;
153 }
154 
155 
156 static void _addLayerTreeNodeToUriList( QgsLayerTreeNode *node, QgsMimeDataUtils::UriList &uris )
157 {
158  if ( QgsLayerTree::isGroup( node ) )
159  {
160  Q_FOREACH ( QgsLayerTreeNode *child, QgsLayerTree::toGroup( node )->children() )
161  _addLayerTreeNodeToUriList( child, uris );
162  }
163  else if ( QgsLayerTree::isLayer( node ) )
164  {
165  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
166  QgsMapLayer *layer = nodeLayer->layer();
167  if ( !layer )
168  return;
169 
171  uri.name = layer->name();
172  uri.uri = layer->dataProvider()->dataSourceUri();
173  uri.providerKey = layer->dataProvider()->name();
174 
175  switch ( layer->type() )
176  {
178  {
179  uri.layerType = QStringLiteral( "vector" );
180  if ( uri.providerKey == QStringLiteral( "memory" ) )
181  {
182  QUrl url = QUrl::fromEncoded( uri.uri.toUtf8() );
183  url.addQueryItem( QStringLiteral( "pid" ), QString::number( QCoreApplication::applicationPid() ) );
184  url.addQueryItem( QStringLiteral( "layerid" ), layer->id() );
185  uri.uri = QString( url.toEncoded() );
186  }
187  break;
188  }
190  {
191  uri.layerType = QStringLiteral( "raster" );
192  break;
193  }
194 
197  {
198  // plugin layers do not have a standard way of storing their URI...
199  return;
200  }
201  }
202  uris << uri;
203  }
204 }
205 
206 QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *> &nodes )
207 {
208  UriList uris;
209  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
210  _addLayerTreeNodeToUriList( node, uris );
211  return uriListToByteArray( uris );
212 }
213 
214 QString QgsMimeDataUtils::encode( const QStringList &items )
215 {
216  QString encoded;
217  // Do not escape colon twice
218  QRegularExpression re( "(?<!\\\\):" );
219  Q_FOREACH ( const QString &item, items )
220  {
221  QString str = item;
222  str.replace( '\\', QLatin1String( "\\\\" ) );
223  str.replace( re, QLatin1String( "\\:" ) );
224  encoded += str + ':';
225  }
226  return encoded.left( encoded.length() - 1 );
227 }
228 
229 QStringList QgsMimeDataUtils::decode( const QString &encoded )
230 {
231  QStringList items;
232  QString item;
233  bool inEscape = false;
234  Q_FOREACH ( QChar c, encoded )
235  {
236  if ( c == '\\' && inEscape )
237  {
238  item += c;
239  }
240  else if ( c == '\\' )
241  {
242  inEscape = true;
243  }
244  else if ( c == ':' && !inEscape )
245  {
246  items.append( item );
247  item.clear();
248  }
249  else
250  {
251  item += c;
252  inEscape = false;
253  }
254  }
255  items.append( item );
256  return items;
257 }
258 
259 
260 QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList &layers )
261 {
262  QByteArray encodedData;
263 
264  QDataStream stream( &encodedData, QIODevice::WriteOnly );
265  Q_FOREACH ( const Uri &u, layers )
266  {
267  stream << u.data();
268  }
269  return encodedData;
270 }
QString layerType
Type of URI.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
Base class for all map layer types.
Definition: qgsmaplayer.h:64
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
virtual QgsDataProvider * dataProvider()
Returns the layer&#39;s data provider, it may be null.
#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.
QgsMapLayer::LayerType type() const
Returns the type of the layer.
virtual QString name() const =0
Returns a provider name.
static bool isUriList(const QMimeData *data)
Added in 3.2.
Definition: qgsmaplayer.h:111
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
QString data() const
Returns encoded representation of the object.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
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. ...
QgsMapLayer * layer() const
Returns the map layer associated with this node.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:430
QList< QgsMimeDataUtils::Uri > UriList
QString providerKey
For "vector" / "raster" type: provider id.
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:89
QString name
Definition: qgsmaplayer.h:68
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.
Represents a vector layer which manages a vector based data sets.
Layer tree node points to a map layer.