QGIS API Documentation  2.99.0-Master (9caa722)
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 
28 static const char *QGIS_URILIST_MIMETYPE = "application/x-vnd.qgis.qgis.uri";
29 
30 QgsMimeDataUtils::Uri::Uri( QString &encData )
31 {
32  QgsDebugMsg( "encData: " + encData );
33  QStringList decoded = decode( encData );
34  if ( decoded.size() < 4 )
35  return;
36 
37  layerType = decoded[0];
38  providerKey = decoded[1];
39  name = decoded[2];
40  uri = decoded[3];
41 
42  if ( layerType == QLatin1String( "raster" ) && decoded.size() == 6 )
43  {
44  supportedCrs = decode( decoded[4] );
45  supportedFormats = decode( decoded[5] );
46  }
47  else
48  {
49  supportedCrs.clear();
50  supportedFormats.clear();
51  }
52 
53  QgsDebugMsg( QString( "type:%1 key:%2 name:%3 uri:%4 supportedCRS:%5 supportedFormats:%6" )
54  .arg( layerType, providerKey, name, uri,
55  supportedCrs.join( ", " ),
56  supportedFormats.join( ", " ) ) );
57 }
58 
60 {
61  return encode( QStringList() << layerType << providerKey << name << uri << encode( supportedCrs ) << encode( supportedFormats ) );
62 }
63 
64 QgsVectorLayer *QgsMimeDataUtils::Uri::vectorLayer( bool &owner, QString &error ) const
65 {
66  owner = false;
67  if ( layerType != QLatin1String( "vector" ) )
68  {
69  error = QObject::tr( "%1: Not a vector layer." ).arg( name );
70  return nullptr;
71  }
72  if ( providerKey == QLatin1String( "memory" ) )
73  {
74  QUrl url = QUrl::fromEncoded( uri.toUtf8() );
75  if ( !url.hasQueryItem( QStringLiteral( "pid" ) ) || !url.hasQueryItem( QStringLiteral( "layerid" ) ) )
76  {
77  error = QObject::tr( "Memory layer uri does not contain process or layer id." );
78  return nullptr;
79  }
80  qint64 pid = url.queryItemValue( QStringLiteral( "pid" ) ).toLongLong();
81  if ( pid != QCoreApplication::applicationPid() )
82  {
83  error = QObject::tr( "Memory layer from another QGIS instance." );
84  return nullptr;
85  }
86  QString layerId = url.queryItemValue( QStringLiteral( "layerid" ) );
87  QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer *>( QgsProject::instance()->mapLayer( layerId ) );
88  if ( !vectorLayer )
89  {
90  error = QObject::tr( "Cannot get memory layer." );
91  return nullptr;
92  }
93  return vectorLayer;
94  }
95  owner = true;
96  return new QgsVectorLayer( uri, name, providerKey );
97 }
98 
99 QgsRasterLayer *QgsMimeDataUtils::Uri::rasterLayer( bool &owner, QString &error ) const
100 {
101  owner = false;
102  if ( layerType != QLatin1String( "raster" ) )
103  {
104  error = QObject::tr( "%1: Not a raster layer." ).arg( name );
105  return nullptr;
106  }
107  owner = true;
108  return new QgsRasterLayer( uri, name, providerKey );
109 }
110 
111 // -----
112 
113 bool QgsMimeDataUtils::isUriList( const QMimeData *data )
114 {
115  return data->hasFormat( QGIS_URILIST_MIMETYPE );
116 }
117 
119 {
120  QMimeData *mimeData = new QMimeData();
121 
122  mimeData->setData( QGIS_URILIST_MIMETYPE, uriListToByteArray( layers ) );
123  return mimeData;
124 }
125 
126 
128 {
129  QByteArray encodedData = data->data( QGIS_URILIST_MIMETYPE );
130  QDataStream stream( &encodedData, QIODevice::ReadOnly );
131  QString xUri; // extended uri: layer_type:provider_key:uri
132  UriList list;
133  while ( !stream.atEnd() )
134  {
135  stream >> xUri;
136  QgsDebugMsg( xUri );
137  list.append( Uri( xUri ) );
138  }
139  return list;
140 }
141 
142 
143 static void _addLayerTreeNodeToUriList( QgsLayerTreeNode *node, QgsMimeDataUtils::UriList &uris )
144 {
145  if ( QgsLayerTree::isGroup( node ) )
146  {
147  Q_FOREACH ( QgsLayerTreeNode *child, QgsLayerTree::toGroup( node )->children() )
148  _addLayerTreeNodeToUriList( child, uris );
149  }
150  else if ( QgsLayerTree::isLayer( node ) )
151  {
152  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
153  QgsMapLayer *layer = nodeLayer->layer();
154  if ( !layer )
155  return;
156 
158  uri.name = layer->name();
159  uri.uri = layer->dataProvider()->dataSourceUri();
160  uri.providerKey = layer->dataProvider()->name();
161  if ( layer->type() == QgsMapLayer::VectorLayer )
162  {
163  uri.layerType = QStringLiteral( "vector" );
164  if ( uri.providerKey == QStringLiteral( "memory" ) )
165  {
166  QUrl url = QUrl::fromEncoded( uri.uri.toUtf8() );
167  url.addQueryItem( QStringLiteral( "pid" ), QString::number( QCoreApplication::applicationPid() ) );
168  url.addQueryItem( QStringLiteral( "layerid" ), layer->id() );
169  uri.uri = QString( url.toEncoded() );
170  }
171  }
172  else if ( layer->type() == QgsMapLayer::RasterLayer )
173  {
174  uri.layerType = QStringLiteral( "raster" );
175  }
176  else
177  {
178  // plugin layers do not have a standard way of storing their URI...
179  return;
180  }
181  uris << uri;
182  }
183 }
184 
185 QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *> &nodes )
186 {
187  UriList uris;
188  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
189  _addLayerTreeNodeToUriList( node, uris );
190  return uriListToByteArray( uris );
191 }
192 
193 QString QgsMimeDataUtils::encode( const QStringList &items )
194 {
195  QString encoded;
196  Q_FOREACH ( const QString &item, items )
197  {
198  QString str = item;
199  str.replace( '\\', QLatin1String( "\\\\" ) );
200  str.replace( ':', QLatin1String( "\\:" ) );
201  encoded += str + ':';
202  }
203  return encoded.left( encoded.length() - 1 );
204 }
205 
206 QStringList QgsMimeDataUtils::decode( const QString &encoded )
207 {
208  QStringList items;
209  QString item;
210  bool inEscape = false;
211  Q_FOREACH ( QChar c, encoded )
212  {
213  if ( c == '\\' && inEscape )
214  {
215  item += c;
216  }
217  else if ( c == '\\' )
218  {
219  inEscape = true;
220  }
221  else if ( c == ':' && !inEscape )
222  {
223  items.append( item );
224  item = QLatin1String( "" );
225  }
226  else
227  {
228  item += c;
229  inEscape = false;
230  }
231  }
232  items.append( item );
233  return items;
234 }
235 
236 
237 QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList &layers )
238 {
239  QByteArray encodedData;
240 
241  QDataStream stream( &encodedData, QIODevice::WriteOnly );
242  Q_FOREACH ( const Uri &u, layers )
243  {
244  stream << u.data();
245  }
246  return encodedData;
247 }
QString layerType
Type of URI. Recognized types: "vector" / "raster" / "plugin" / "custom".
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:74
Base class for all map layer types.
Definition: qgsmaplayer.h:54
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:42
virtual QgsDataProvider * dataProvider()
Returns the layer&#39;s data provider.
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
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:63
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
Return a provider name.
static bool isUriList(const QMimeData *data)
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
Get the data source specification.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:52
This class is a base class for nodes in a layer tree.
QgsVectorLayer * vectorLayer(bool &owner, QString &error) const
Get vector layer from uri if possible, otherwise returns 0 and error is set.
Uri()=default
Constructs invalid URI.
QgsMapLayer * layer() const
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:379
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.
QString name
Definition: qgsmaplayer.h:58
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
Get 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.