QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsvirtuallayerdefinition.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvirtuallayerdefinition.cpp
3 begin : December 2015
4 copyright : (C) 2015 Hugo Mercier, Oslandia
5 email : hugo dot mercier at oslandia dot com
6  ***************************************************************************/
7 
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include <QUrl>
18 #include <QRegExp>
19 #include <QStringList>
20 
22 #include "qgsvectorlayer.h"
23 #include "qgsvectordataprovider.h"
24 
26  : mFilePath( filePath )
27  , mGeometryWkbType( QgsWKBTypes::Unknown )
28  , mGeometrySrid( 0 )
29 {
30 }
31 
33 {
35 
36  def.setFilePath( url.toLocalFile() );
37 
38  // regexp for column name
39  const QString columnNameRx( "[a-zA-Z_\x80-\xFF][a-zA-Z0-9_\x80-\xFF]*" );
40 
42 
43  int layerIdx = 0;
45  for ( int i = 0; i < items.size(); i++ )
46  {
47  QString key = items.at( i ).first;
48  QString value = items.at( i ).second;
49  if ( key == "layer_ref" )
50  {
51  layerIdx++;
52  // layer id, with optional layer_name
53  int pos = value.indexOf( ':' );
54  QString layerId, vlayerName;
55  if ( pos == -1 )
56  {
57  layerId = value;
58  vlayerName = QString( "vtab%1" ).arg( layerIdx );
59  }
60  else
61  {
62  layerId = value.left( pos );
63  vlayerName = QUrl::fromPercentEncoding( value.mid( pos + 1 ).toUtf8() );
64  }
65  // add the layer to the list
66  def.addSource( vlayerName, layerId );
67  }
68  else if ( key == "layer" )
69  {
70  layerIdx++;
71  // syntax: layer=provider:url_encoded_source_URI(:name(:encoding)?)?
72  int pos = value.indexOf( ':' );
73  if ( pos != -1 )
74  {
75  QString providerKey, source, vlayerName, encoding = "UTF-8";
76 
77  providerKey = value.left( pos );
78  int pos2 = value.indexOf( ':', pos + 1 );
79  if ( pos2 - pos == 2 )
80  pos2 = value.indexOf( ':', pos + 3 );
81  if ( pos2 != -1 )
82  {
83  source = QUrl::fromPercentEncoding( value.mid( pos + 1, pos2 - pos - 1 ).toUtf8() );
84  int pos3 = value.indexOf( ':', pos2 + 1 );
85  if ( pos3 != -1 )
86  {
87  vlayerName = QUrl::fromPercentEncoding( value.mid( pos2 + 1, pos3 - pos2 - 1 ).toUtf8() );
88  encoding = value.mid( pos3 + 1 );
89  }
90  else
91  {
92  vlayerName = QUrl::fromPercentEncoding( value.mid( pos2 + 1 ).toUtf8() );
93  }
94  }
95  else
96  {
97  source = QUrl::fromPercentEncoding( value.mid( pos + 1 ).toUtf8() );
98  vlayerName = QString( "vtab%1" ).arg( layerIdx );
99  }
100 
101  def.addSource( vlayerName, source, providerKey, encoding );
102  }
103  }
104  else if ( key == "geometry" )
105  {
106  // geometry field definition, optional
107  // geometry_column(:wkb_type:srid)?
108  QRegExp reGeom( "(" + columnNameRx + ")(?::([a-zA-Z0-9]+):(\\d+))?" );
109  int pos = reGeom.indexIn( value );
110  if ( pos >= 0 )
111  {
112  def.setGeometryField( reGeom.cap( 1 ) );
113  if ( reGeom.captureCount() > 1 )
114  {
115  // not used by the spatialite provider for now ...
116  QgsWKBTypes::Type wkbType = QgsWKBTypes::parseType( reGeom.cap( 2 ) );
117  if ( wkbType == QgsWKBTypes::Unknown )
118  {
119  wkbType = static_cast<QgsWKBTypes::Type>( reGeom.cap( 2 ).toLong() );
120  }
121  def.setGeometryWkbType( wkbType );
122  def.setGeometrySrid( reGeom.cap( 3 ).toLong() );
123  }
124  }
125  }
126  else if ( key == "nogeometry" )
127  {
129  }
130  else if ( key == "uid" )
131  {
132  def.setUid( value );
133  }
134  else if ( key == "query" )
135  {
136  // url encoded query
137  def.setQuery( QUrl::fromPercentEncoding( value.toUtf8() ) );
138  }
139  else if ( key == "field" )
140  {
141  // field_name:type (int, real, text)
142  QRegExp reField( "(" + columnNameRx + "):(int|real|text)" );
143  int pos = reField.indexIn( value );
144  if ( pos >= 0 )
145  {
146  QString fieldName( reField.cap( 1 ) );
147  QString fieldType( reField.cap( 2 ) );
148  if ( fieldType == "int" )
149  {
150  fields.append( QgsField( fieldName, QVariant::Int, fieldType ) );
151  }
152  else if ( fieldType == "real" )
153  {
154  fields.append( QgsField( fieldName, QVariant::Double, fieldType ) );
155  }
156  if ( fieldType == "text" )
157  {
158  fields.append( QgsField( fieldName, QVariant::String, fieldType ) );
159  }
160  }
161  }
162  }
163  def.setFields( fields );
164 
165  return def;
166 }
167 
169 {
170  QUrl url;
171  if ( !filePath().isEmpty() )
172  url = QUrl::fromLocalFile( filePath() );
173 
174  Q_FOREACH ( const QgsVirtualLayerDefinition::SourceLayer& l, sourceLayers() )
175  {
176  if ( l.isReferenced() )
177  url.addQueryItem( "layer_ref", QString( "%1:%2" ).arg( l.reference(), l.name() ) );
178  else
179  url.addEncodedQueryItem( "layer", QString( "%1:%4:%2:%3" ) // the order is important, since the 4th argument may contain '%2' as well
180  .arg( l.provider(),
182  l.encoding(),
183  QString( QUrl::toPercentEncoding( l.source() ) ) ).toUtf8() );
184  }
185 
186  if ( !query().isEmpty() )
187  {
188  url.addQueryItem( "query", query() );
189  }
190 
191  if ( !uid().isEmpty() )
192  url.addQueryItem( "uid", uid() );
193 
195  url.addQueryItem( "nogeometry", "" );
196  else if ( !geometryField().isEmpty() )
197  {
198  if ( hasDefinedGeometry() )
199  url.addQueryItem( "geometry", QString( "%1:%2:%3" ).arg( geometryField() ). arg( geometryWkbType() ).arg( geometrySrid() ).toUtf8() );
200  else
201  url.addQueryItem( "geometry", geometryField() );
202  }
203 
204  Q_FOREACH ( const QgsField& f, fields() )
205  {
206  if ( f.type() == QVariant::Int )
207  url.addQueryItem( "field", f.name() + ":int" );
208  else if ( f.type() == QVariant::Double )
209  url.addQueryItem( "field", f.name() + ":real" );
210  else if ( f.type() == QVariant::String )
211  url.addQueryItem( "field", f.name() + ":text" );
212  }
213 
214  return url;
215 }
216 
218 {
219  return QString( toUrl().toEncoded() );
220 }
221 
222 void QgsVirtualLayerDefinition::addSource( const QString& name, const QString& ref )
223 {
224  mSourceLayers.append( SourceLayer( name, ref ) );
225 }
226 
227 void QgsVirtualLayerDefinition::addSource( const QString& name, const QString& source, const QString& provider, const QString& encoding )
228 {
229  mSourceLayers.append( SourceLayer( name, source, provider, encoding ) );
230 }
231 
233 {
234  Q_FOREACH ( const QgsVirtualLayerDefinition::SourceLayer& l, sourceLayers() )
235  {
236  if ( l.name() == name )
237  {
238  return true;
239  }
240  }
241  return false;
242 }
243 
245 {
246  Q_FOREACH ( const QgsVirtualLayerDefinition::SourceLayer& l, sourceLayers() )
247  {
248  if ( l.isReferenced() )
249  {
250  return true;
251  }
252  }
253  return false;
254 }
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString cap(int nth) const
QString name
Definition: qgsfield.h:52
bool isReferenced() const
Is it a live layer or not ?
const SourceLayers & sourceLayers() const
Get access to the source layers.
bool hasReferencedLayers() const
Convenience method to test whether the definition has referenced (live) layers.
void setFields(const QgsFields &fields)
Set field definitions.
QString name() const
Name of the layer.
QString uid() const
Get the name of the field with unique identifiers.
const T & at(int i) const
QString encoding() const
Optional encoding for the provider.
Container of fields for a vector layer.
Definition: qgsfield.h:252
QString toString() const
Convert into a QString that can be read by the virtual layer provider.
static QgsVirtualLayerDefinition fromUrl(const QUrl &url)
Constructor to build a definition from a QUrl The path part of the URL is extracted as well as the fo...
QString source() const
The source url used by the provider to build the layer.
void addEncodedQueryItem(const QByteArray &key, const QByteArray &value)
void addSource(const QString &name, const QString &ref)
Add a live layer source layer.
int size() const
void setFilePath(const QString &filePath)
Set the file path.
QUrl toUrl() const
Convert the definition into a QUrl.
QString filePath() const
Get the file path. May be empty.
int indexIn(const QString &str, int offset, CaretMode caretMode) const
QString reference() const
The reference (id) of the live layer.
void append(const T &value)
void setQuery(const QString &query)
Set the SQL query.
int captureCount() const
void setGeometryField(const QString &geometryField)
Set the name of the geometry field.
bool isEmpty() const
QList< QPair< QByteArray, QByteArray > > encodedQueryItems() const
const QgsFields & fields() const
Get field definitions.
QString geometryField() const
Get the name of the geometry field. Empty if no geometry field.
void setGeometryWkbType(QgsWKBTypes::Type t)
Set the type of the geometry.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfield.cpp:346
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
QString fromPercentEncoding(const QByteArray &input)
bool hasSourceLayer(const QString &name) const
Convenience method to test if a given source layer is part of the definition.
QString toLocalFile() const
long toLong(bool *ok, int base) const
QString mid(int position, int n) const
bool hasDefinedGeometry() const
Convenient method to test if the geometry is defined (not NoGeometry and not Unknown) ...
Handles storage of information regarding WKB types and their properties.
Definition: qgswkbtypes.h:36
void setUid(const QString &uid)
Set the name of the field with unique identifiers.
QgsWKBTypes::Type geometryWkbType() const
Get the type of the geometry QgsWKBTypes::NoGeometry to hide any geometry QgsWKBTypes::Unknown for un...
QByteArray toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include)
void setGeometrySrid(long srid)
Set the SRID of the geometry.
QString left(int n) const
void addQueryItem(const QString &key, const QString &value)
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
Definition: qgswkbtypes.cpp:32
QString query() const
Get the SQL query.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:97
QgsVirtualLayerDefinition(const QString &filePath="")
Constructor with an optional file path.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
A SourceLayer is either a reference to a live layer in the registry or all the parameters needed to l...
Class to manipulate the definition of a virtual layer.
long geometrySrid() const
Get the SRID of the geometry.
QUrl fromLocalFile(const QString &localFile)
QByteArray toUtf8() const