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