QGIS API Documentation  3.2.0-Bonn (bc43194)
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( QString( "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" ) );
88  QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer *>( QgsProject::instance()->mapLayer( 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  if ( layer->type() == QgsMapLayer::VectorLayer )
175  {
176  uri.layerType = QStringLiteral( "vector" );
177  if ( uri.providerKey == QStringLiteral( "memory" ) )
178  {
179  QUrl url = QUrl::fromEncoded( uri.uri.toUtf8() );
180  url.addQueryItem( QStringLiteral( "pid" ), QString::number( QCoreApplication::applicationPid() ) );
181  url.addQueryItem( QStringLiteral( "layerid" ), layer->id() );
182  uri.uri = QString( url.toEncoded() );
183  }
184  }
185  else if ( layer->type() == QgsMapLayer::RasterLayer )
186  {
187  uri.layerType = QStringLiteral( "raster" );
188  }
189  else
190  {
191  // plugin layers do not have a standard way of storing their URI...
192  return;
193  }
194  uris << uri;
195  }
196 }
197 
198 QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *> &nodes )
199 {
200  UriList uris;
201  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
202  _addLayerTreeNodeToUriList( node, uris );
203  return uriListToByteArray( uris );
204 }
205 
206 QString QgsMimeDataUtils::encode( const QStringList &items )
207 {
208  QString encoded;
209  // Do not escape colon twice
210  QRegularExpression re( "(?<!\\\\):" );
211  Q_FOREACH ( const QString &item, items )
212  {
213  QString str = item;
214  str.replace( '\\', QLatin1String( "\\\\" ) );
215  str.replace( re, QLatin1String( "\\:" ) );
216  encoded += str + ':';
217  }
218  return encoded.left( encoded.length() - 1 );
219 }
220 
221 QStringList QgsMimeDataUtils::decode( const QString &encoded )
222 {
223  QStringList items;
224  QString item;
225  bool inEscape = false;
226  Q_FOREACH ( QChar c, encoded )
227  {
228  if ( c == '\\' && inEscape )
229  {
230  item += c;
231  }
232  else if ( c == '\\' )
233  {
234  inEscape = true;
235  }
236  else if ( c == ':' && !inEscape )
237  {
238  items.append( item );
239  item.clear();
240  }
241  else
242  {
243  item += c;
244  inEscape = false;
245  }
246  }
247  items.append( item );
248  return items;
249 }
250 
251 
252 QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList &layers )
253 {
254  QByteArray encodedData;
255 
256  QDataStream stream( &encodedData, QIODevice::WriteOnly );
257  Q_FOREACH ( const Uri &u, layers )
258  {
259  stream << u.data();
260  }
261  return encodedData;
262 }
QString layerType
Type of URI. Recognized types: "vector" / "raster" / "mesh" / "plugin" / "custom" / "project"...
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
Base class for all map layer types.
Definition: qgsmaplayer.h:61
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.
#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)
QStringList supportedFormats
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)
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 0 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 0 and error is set.
QgsMapLayer * layer() const
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
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:90
QString name
Definition: qgsmaplayer.h:65
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 0 and error is set.
Represents a vector layer which manages a vector based data sets.
Layer tree node points to a map layer.