wfs-server-V4.patch

Michael Douchin, 2012-03-19 04:52 AM

Download (66.5 KB)

View differences:

src/app/qgsprojectproperties.cpp
175 175
    twIdentifyLayers->setCellWidget( i, 2, cb );
176 176
  }
177 177

  
178
  grpWMSServiceCapabilities->setChecked( QgsProject::instance()->readBoolEntry( "WMSServiceCapabilities", "/", false ) );
178
  grpOWSServiceCapabilities->setChecked( QgsProject::instance()->readBoolEntry( "WMSServiceCapabilities", "/", false ) );
179 179
  mWMSTitle->setText( QgsProject::instance()->readEntry( "WMSServiceTitle", "/" ) );
180 180
  mWMSContactOrganization->setText( QgsProject::instance()->readEntry( "WMSContactOrganization", "/", "" ) );
181 181
  mWMSContactPerson->setText( QgsProject::instance()->readEntry( "WMSContactPerson", "/", "" ) );
......
229 229
  bool addWktGeometry = QgsProject::instance()->readBoolEntry( "WMSAddWktGeometry", "/" );
230 230
  mAddWktGeometryCheckBox->setChecked( addWktGeometry );
231 231

  
232
  QStringList wfsLayerIdList = QgsProject::instance()->readListEntry( "WFSLayers", "/" );
233

  
234
  twWFSLayers->setColumnCount( 2 );
235
  twWFSLayers->horizontalHeader()->setVisible( true );
236
  twWFSLayers->setRowCount( mapLayers.size() );
237

  
238
  i = 0;
239
  int j = 0;
240
  for ( QMap<QString, QgsMapLayer*>::const_iterator it = mapLayers.constBegin(); it != mapLayers.constEnd(); it++, i++ )
241
  {
242
    currentLayer = it.value();
243
    if ( currentLayer->type() == QgsMapLayer::VectorLayer )
244
    {
245

  
246
    QTableWidgetItem *twi = new QTableWidgetItem( QString::number( j ) );
247
    twWFSLayers->setVerticalHeaderItem( j, twi );
248

  
249
    twi = new QTableWidgetItem( currentLayer->name() );
250
    twi->setData( Qt::UserRole, it.key() );
251
    twi->setFlags( twi->flags() & ~Qt::ItemIsEditable );
252
    twWFSLayers->setItem( j, 0, twi );
253

  
254
    QCheckBox *cb = new QCheckBox();
255
    cb->setChecked( wfsLayerIdList.contains( currentLayer->id() ) );
256
    twWFSLayers->setCellWidget( j, 1, cb );
257
    j++;
258

  
259
    }
260
  }
261
  twWFSLayers->setRowCount( j );
262
  twWFSLayers->verticalHeader()->setResizeMode( QHeaderView::ResizeToContents );
263

  
232 264
  restoreState();
233 265
}
234 266

  
......
380 412

  
381 413
  QgsProject::instance()->writeEntry( "Identify", "/disabledLayers", noIdentifyLayerList );
382 414

  
383
  QgsProject::instance()->writeEntry( "WMSServiceCapabilities", "/", grpWMSServiceCapabilities->isChecked() );
415
  QgsProject::instance()->writeEntry( "WMSServiceCapabilities", "/", grpOWSServiceCapabilities->isChecked() );
384 416
  QgsProject::instance()->writeEntry( "WMSServiceTitle", "/", mWMSTitle->text() );
385 417
  QgsProject::instance()->writeEntry( "WMSContactOrganization", "/", mWMSContactOrganization->text() );
386 418
  QgsProject::instance()->writeEntry( "WMSContactPerson", "/", mWMSContactPerson->text() );
......
428 460

  
429 461
  QgsProject::instance()->writeEntry( "WMSAddWktGeometry", "/", mAddWktGeometryCheckBox->isChecked() );
430 462

  
463
  QStringList wfsLayerList;
464
  for ( int i = 0; i < twWFSLayers->rowCount(); i++ )
465
  {
466
    QCheckBox *cb = qobject_cast<QCheckBox *>( twWFSLayers->cellWidget( i, 1 ) );
467
    if ( cb && cb->isChecked() )
468
    {
469
      QString id = twWFSLayers->item( i, 0 )->data( Qt::UserRole ).toString();
470
      wfsLayerList << id;
471
    }
472
  }
473
  QgsProject::instance()->writeEntry( "WFSLayers", "/", wfsLayerList );
474

  
431 475
  //todo XXX set canvas color
432 476
  emit refresh();
433 477
}
src/core/qgsgeometry.cpp
4185 4185
  }
4186 4186
}
4187 4187

  
4188
QString QgsGeometry::exportToGeoJSON()
4189
{
4190
  QgsDebugMsg( "entered." );
4191

  
4192
  // TODO: implement with GEOS
4193
  if ( mDirtyWkb )
4194
  {
4195
    exportGeosToWkb();
4196
  }
4197

  
4198
  if ( !mGeometry )
4199
  {
4200
    QgsDebugMsg( "WKB geometry not available!" );
4201
    return QString::null;
4202
  }
4203

  
4204
  QGis::WkbType wkbType;
4205
  bool hasZValue = false;
4206
  double *x, *y;
4207

  
4208
  QString mWkt; // TODO: rename
4209

  
4210
  // Will this really work when mGeometry[0] == 0 ???? I (gavin) think not.
4211
  //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4];
4212
  memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) );
4213

  
4214
  switch ( wkbType )
4215
  {
4216
    case QGis::WKBPoint25D:
4217
    case QGis::WKBPoint:
4218
    {
4219
      mWkt += "{ \"type\": \"Point\", \"coordinates\": [";
4220
      x = ( double * )( mGeometry + 5 );
4221
      mWkt += QString::number( *x, 'f', 6 );
4222
      mWkt += ", ";
4223
      y = ( double * )( mGeometry + 5 + sizeof( double ) );
4224
      mWkt += QString::number( *y, 'f', 6 );
4225
      mWkt += "] }";
4226
      return mWkt;
4227
    }
4228

  
4229
    case QGis::WKBLineString25D:
4230
      hasZValue = true;
4231
    case QGis::WKBLineString:
4232
    {
4233
      QgsDebugMsg( "LINESTRING found" );
4234
      unsigned char *ptr;
4235
      int *nPoints;
4236
      int idx;
4237

  
4238
      mWkt += "{ \"type\": \"LineString\", \"coordinates\": [ ";
4239
      // get number of points in the line
4240
      ptr = mGeometry + 5;
4241
      nPoints = ( int * ) ptr;
4242
      ptr = mGeometry + 1 + 2 * sizeof( int );
4243
      for ( idx = 0; idx < *nPoints; ++idx )
4244
      {
4245
        if ( idx != 0 )
4246
        {
4247
          mWkt += ", ";
4248
        }
4249
        mWkt += "[";
4250
        x = ( double * ) ptr;
4251
        mWkt += QString::number( *x, 'f', 6 );
4252
        mWkt += ", ";
4253
        ptr += sizeof( double );
4254
        y = ( double * ) ptr;
4255
        mWkt += QString::number( *y, 'f', 6 );
4256
        ptr += sizeof( double );
4257
        if ( hasZValue )
4258
        {
4259
          ptr += sizeof( double );
4260
        }
4261
        mWkt += "]";
4262
      }
4263
      mWkt += " ] }";
4264
      return mWkt;
4265
    }
4266

  
4267
    case QGis::WKBPolygon25D:
4268
      hasZValue = true;
4269
    case QGis::WKBPolygon:
4270
    {
4271
      QgsDebugMsg( "POLYGON found" );
4272
      unsigned char *ptr;
4273
      int idx, jdx;
4274
      int *numRings, *nPoints;
4275

  
4276
      mWkt += "{ \"type\": \"Polygon\", \"coordinates\": [ ";
4277
      // get number of rings in the polygon
4278
      numRings = ( int * )( mGeometry + 1 + sizeof( int ) );
4279
      if ( !( *numRings ) )  // sanity check for zero rings in polygon
4280
      {
4281
        return QString();
4282
      }
4283
      int *ringStart; // index of first point for each ring
4284
      int *ringNumPoints; // number of points in each ring
4285
      ringStart = new int[*numRings];
4286
      ringNumPoints = new int[*numRings];
4287
      ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring
4288
      for ( idx = 0; idx < *numRings; idx++ )
4289
      {
4290
        if ( idx != 0 )
4291
        {
4292
          mWkt += ", ";
4293
        }
4294
        mWkt += "[ ";
4295
        // get number of points in the ring
4296
        nPoints = ( int * ) ptr;
4297
        ringNumPoints[idx] = *nPoints;
4298
        ptr += 4;
4299

  
4300
        for ( jdx = 0; jdx < *nPoints; jdx++ )
4301
        {
4302
          if ( jdx != 0 )
4303
          {
4304
            mWkt += ", ";
4305
          }
4306
          mWkt += "[";
4307
          x = ( double * ) ptr;
4308
          mWkt += QString::number( *x, 'f', 6 );
4309
          mWkt += ", ";
4310
          ptr += sizeof( double );
4311
          y = ( double * ) ptr;
4312
          mWkt += QString::number( *y, 'f', 6 );
4313
          ptr += sizeof( double );
4314
          if ( hasZValue )
4315
          {
4316
            ptr += sizeof( double );
4317
          }
4318
          mWkt += "]";
4319
        }
4320
        mWkt += " ]";
4321
      }
4322
      mWkt += " ] }";
4323
      delete [] ringStart;
4324
      delete [] ringNumPoints;
4325
      return mWkt;
4326
    }
4327

  
4328
    case QGis::WKBMultiPoint25D:
4329
      hasZValue = true;
4330
    case QGis::WKBMultiPoint:
4331
    {
4332
      unsigned char *ptr;
4333
      int idx;
4334
      int *nPoints;
4335

  
4336
      mWkt += "{ \"type\": \"MultiPoint\", \"coordinates\": [ ";
4337
      nPoints = ( int* )( mGeometry + 5 );
4338
      ptr = mGeometry + 5 + sizeof( int );
4339
      for ( idx = 0; idx < *nPoints; ++idx )
4340
      {
4341
        ptr += ( 1 + sizeof( int ) );
4342
        if ( idx != 0 )
4343
        {
4344
          mWkt += ", ";
4345
        }
4346
        mWkt += "[";
4347
        x = ( double * )( ptr );
4348
        mWkt += QString::number( *x, 'f', 6 );
4349
        mWkt += ", ";
4350
        ptr += sizeof( double );
4351
        y = ( double * )( ptr );
4352
        mWkt += QString::number( *y, 'f', 6 );
4353
        ptr += sizeof( double );
4354
        if ( hasZValue )
4355
        {
4356
          ptr += sizeof( double );
4357
        }
4358
        mWkt += "]";
4359
      }
4360
      mWkt += " ] }";
4361
      return mWkt;
4362
    }
4363

  
4364
    case QGis::WKBMultiLineString25D:
4365
      hasZValue = true;
4366
    case QGis::WKBMultiLineString:
4367
    {
4368
      QgsDebugMsg( "MULTILINESTRING found" );
4369
      unsigned char *ptr;
4370
      int idx, jdx, numLineStrings;
4371
      int *nPoints;
4372

  
4373
      mWkt += "{ \"type\": \"MultiLineString\", \"coordinates\": [ ";
4374
      numLineStrings = ( int )( mGeometry[5] );
4375
      ptr = mGeometry + 9;
4376
      for ( jdx = 0; jdx < numLineStrings; jdx++ )
4377
      {
4378
        if ( jdx != 0 )
4379
        {
4380
          mWkt += ", ";
4381
        }
4382
        mWkt += "[ ";
4383
        ptr += 5; // skip type since we know its 2
4384
        nPoints = ( int * ) ptr;
4385
        ptr += sizeof( int );
4386
        for ( idx = 0; idx < *nPoints; idx++ )
4387
        {
4388
          if ( idx != 0 )
4389
          {
4390
            mWkt += ", ";
4391
          }
4392
          mWkt += "[";
4393
          x = ( double * ) ptr;
4394
          mWkt += QString::number( *x, 'f', 6 );
4395
          ptr += sizeof( double );
4396
          mWkt += ", ";
4397
          y = ( double * ) ptr;
4398
          mWkt += QString::number( *y, 'f', 6 );
4399
          ptr += sizeof( double );
4400
          if ( hasZValue )
4401
          {
4402
            ptr += sizeof( double );
4403
          }
4404
          mWkt += "]";
4405
        }
4406
        mWkt += " ]";
4407
      }
4408
      mWkt += " ] }";
4409
      return mWkt;
4410
    }
4411

  
4412
    case QGis::WKBMultiPolygon25D:
4413
      hasZValue = true;
4414
    case QGis::WKBMultiPolygon:
4415
    {
4416
      QgsDebugMsg( "MULTIPOLYGON found" );
4417
      unsigned char *ptr;
4418
      int idx, jdx, kdx;
4419
      int *numPolygons, *numRings, *nPoints;
4420

  
4421
      mWkt += "{ \"type\": \"MultiPolygon\", \"coordinates\": [ ";
4422
      ptr = mGeometry + 5;
4423
      numPolygons = ( int * ) ptr;
4424
      ptr = mGeometry + 9;
4425
      for ( kdx = 0; kdx < *numPolygons; kdx++ )
4426
      {
4427
        if ( kdx != 0 )
4428
        {
4429
          mWkt += ", ";
4430
        }
4431
        mWkt += "[ ";
4432
        ptr += 5;
4433
        numRings = ( int * ) ptr;
4434
        ptr += 4;
4435
        for ( idx = 0; idx < *numRings; idx++ )
4436
        {
4437
          if ( idx != 0 )
4438
          {
4439
            mWkt += ", ";
4440
          }
4441
          mWkt += "[ ";
4442
          nPoints = ( int * ) ptr;
4443
          ptr += 4;
4444
          for ( jdx = 0; jdx < *nPoints; jdx++ )
4445
          {
4446
            if ( jdx != 0 )
4447
            {
4448
              mWkt += ", ";
4449
            }
4450
            mWkt += "[";
4451
            x = ( double * ) ptr;
4452
            mWkt += QString::number( *x, 'f', 6 );
4453
            ptr += sizeof( double );
4454
            mWkt += ", ";
4455
            y = ( double * ) ptr;
4456
            mWkt += QString::number( *y, 'f', 6 );
4457
            ptr += sizeof( double );
4458
            if ( hasZValue )
4459
            {
4460
              ptr += sizeof( double );
4461
            }
4462
            mWkt += "]";
4463
          }
4464
          mWkt += " ]";
4465
        }
4466
        mWkt += " ]";
4467
      }
4468
      mWkt += " ] }";
4469
      return mWkt;
4470
    }
4471

  
4472
    default:
4473
      QgsDebugMsg( "error: mGeometry type not recognized" );
4474
      return QString::null;
4475
  }
4476
}
4477

  
4188 4478
bool QgsGeometry::exportWkbToGeos()
4189 4479
{
4190 4480
  QgsDebugMsgLevel( "entered.", 3 );
src/core/qgsgeometry.h
361 361
     */
362 362
    QString exportToWkt();
363 363

  
364
    /** Exports the geometry to mGeoJSON
365
        @return true in case of success and false else
366
     */
367
    QString exportToGeoJSON();
368

  
364 369
    /* Accessor functions for getting geometry data */
365 370

  
366 371
    /** return contents of the geometry as a point
src/mapserver/CMakeLists.txt
28 28
  qgssldparser.cpp
29 29
  qgssldrenderer.cpp
30 30
  qgswmsserver.cpp
31
  qgswfsserver.cpp
31 32
  qgsmapserviceexception.cpp
32 33
  qgsmslayercache.cpp
33 34
  qgsfilter.cpp
src/mapserver/qgis_map_serv.cpp
26 26
#include "qgsproviderregistry.h"
27 27
#include "qgslogger.h"
28 28
#include "qgswmsserver.h"
29
#include "qgswfsserver.h"
29 30
#include "qgsmaprenderer.h"
30 31
#include "qgsmapserviceexception.h"
31 32
#include "qgsprojectparser.h"
......
264 265

  
265 266
    //request to WMS?
266 267
    QString serviceString;
267
#ifndef QGISDEBUG
268
    serviceString = parameterMap.value( "SERVICE", "WMS" );
269
#else
270 268
    paramIt = parameterMap.find( "SERVICE" );
271 269
    if ( paramIt == parameterMap.constEnd() )
272 270
    {
271
#ifndef QGISDEBUG
272
      serviceString = parameterMap.value( "SERVICE", "WMS" );
273
#else
273 274
      QgsDebugMsg( "unable to find 'SERVICE' parameter, exiting..." );
274 275
      theRequestHandler->sendServiceException( QgsMapServiceException( "ServiceNotSpecified", "Service not specified. The SERVICE parameter is mandatory" ) );
275 276
      delete theRequestHandler;
276 277
      continue;
278
#endif
277 279
    }
278 280
    else
279 281
    {
280 282
      serviceString = paramIt.value();
281 283
    }
282
#endif
283 284

  
284 285
    QgsWMSServer* theServer = 0;
286
    if ( serviceString == "WFS" )
287
    {
288
      delete theServer;
289
      QgsWFSServer* theServer = 0;
290
      try
291
      {
292
        theServer = new QgsWFSServer( parameterMap );
293
      }
294
      catch ( QgsMapServiceException e ) //admin.sld may be invalid
295
      {
296
        theRequestHandler->sendServiceException( e );
297
        continue;
298
      }
299

  
300
      theServer->setAdminConfigParser( adminConfigParser );
301

  
302

  
303
      //request type
304
      QString request = parameterMap.value( "REQUEST" );
305
      if ( request.isEmpty() )
306
      {
307
        //do some error handling
308
        QgsDebugMsg( "unable to find 'REQUEST' parameter, exiting..." );
309
        theRequestHandler->sendServiceException( QgsMapServiceException( "OperationNotSupported", "Please check the value of the REQUEST parameter" ) );
310
        delete theRequestHandler;
311
        delete theServer;
312
        continue;
313
      }
314

  
315
      if ( request == "GetCapabilities" )
316
      {
317
        QDomDocument capabilitiesDocument;
318
        try
319
        {
320
          capabilitiesDocument = theServer->getCapabilities();
321
        }
322
        catch ( QgsMapServiceException& ex )
323
        {
324
          theRequestHandler->sendServiceException( ex );
325
          delete theRequestHandler;
326
          delete theServer;
327
          continue;
328
        }
329
        QgsDebugMsg( "sending GetCapabilities response" );
330
        theRequestHandler->sendGetCapabilitiesResponse( capabilitiesDocument );
331
        delete theRequestHandler;
332
        delete theServer;
333
        continue;
334
      }
335
      else if ( request == "DescribeFeatureType" )
336
      {
337
        QDomDocument describeDocument;
338
        try
339
        {
340
          describeDocument = theServer->describeFeatureType();
341
        }
342
        catch ( QgsMapServiceException& ex )
343
        {
344
          theRequestHandler->sendServiceException( ex );
345
          delete theRequestHandler;
346
          delete theServer;
347
          continue;
348
        }
349
        QgsDebugMsg( "sending GetCapabilities response" );
350
        theRequestHandler->sendGetCapabilitiesResponse( describeDocument );
351
        delete theRequestHandler;
352
        delete theServer;
353
        continue;
354
      }
355
      else if ( request == "GetFeature" )
356
      {
357
        //output format for GetFeature
358
        QString outputFormat = parameterMap.value( "OUTPUTFORMAT" );
359
        try
360
        {
361
          if ( theServer->getFeature( *theRequestHandler, outputFormat ) != 0 )
362
          {
363
            delete theRequestHandler;
364
            delete theServer;
365
            continue;
366
          } else {
367
            delete theRequestHandler;
368
            delete theServer;
369
            continue;
370
          }
371
        }
372
        catch ( QgsMapServiceException& ex )
373
        {
374
          theRequestHandler->sendServiceException( ex );
375
          delete theRequestHandler;
376
          delete theServer;
377
          continue;
378
        }
379
      }
380

  
381
      return 0;
382
    }
383

  
285 384
    try
286 385
    {
287 386
      theServer = new QgsWMSServer( parameterMap, theMapRenderer );
src/mapserver/qgsconfigparser.h
42 42
    /**Adds layer and style specific capabilities elements to the parent node. This includes the individual layers and styles, their description, native CRS, bounding boxes, etc.*/
43 43
    virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const = 0;
44 44

  
45
    virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const = 0;
46

  
45 47
    /**Returns one or possibly several maplayers for a given layer name and style. If there are several layers, the layers should be drawn in inverse list order.
46 48
       If no layers/style are found, an empty list is returned
47 49
      @param allowCache true if layer can be read from / written to cache*/
......
87 89

  
88 90
    /**Returns an ID-list of layers which are not queryable*/
89 91
    virtual QStringList identifyDisabledLayers() const { return QStringList(); }
92
    /**Returns an ID-list of layers which queryable in WFS service*/
93
    virtual QStringList wfsLayers() const { return QStringList(); }
90 94

  
91 95
    /**Returns a set of supported epsg codes for the capabilities document. An empty list means
92 96
       that all possible CRS should be advertised (which could result in very long capabilities documents)*/
src/mapserver/qgshttprequesthandler.cpp
288 288
  sendHttpResponse( ba, formatToMimeType( mFormat ) );
289 289
}
290 290

  
291
bool QgsHttpRequestHandler::startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const
292
{
293
  if ( !ba )
294
  {
295
    return false;
296
  }
297

  
298
  if ( ba->size() < 1 )
299
  {
300
    return false;
301
  }
302

  
303
  QString format;
304
  if (infoFormat == "GeoJSON")
305
    format = "text/plain";
306
  else
307
    format = "text/xml";
308

  
309
  printf( "Content-Type: " );
310
  printf( format.toLocal8Bit() );
311
  printf( "\n" );
312
  printf( "\n" );
313
  fwrite( ba->data(), ba->size(), 1, FCGI_stdout );
314
  return true;
315
}
316

  
317
void QgsHttpRequestHandler::sendGetFeatureResponse( QByteArray* ba ) const
318
{
319
  if ( !ba )
320
  {
321
    return;
322
  }
323

  
324
  if ( ba->size() < 1 )
325
  {
326
    return;
327
  }
328
  fwrite( ba->data(), ba->size(), 1, FCGI_stdout );
329
}
330

  
331
void QgsHttpRequestHandler::endGetFeatureResponse( QByteArray* ba ) const
332
{
333
  if ( !ba )
334
  {
335
    return;
336
  }
337

  
338
  fwrite( ba->data(), ba->size(), 1, FCGI_stdout );
339
}
340

  
291 341
void QgsHttpRequestHandler::requestStringToParameterMap( const QString& request, QMap<QString, QString>& parameters )
292 342
{
293 343
  parameters.clear();
src/mapserver/qgshttprequesthandler.h
34 34
    virtual void sendServiceException( const QgsMapServiceException& ex ) const;
35 35
    virtual void sendGetStyleResponse( const QDomDocument& doc ) const;
36 36
    virtual void sendGetPrintResponse( QByteArray* ba ) const;
37
    virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const;
38
    virtual void sendGetFeatureResponse( QByteArray* ba ) const;
39
    virtual void endGetFeatureResponse( QByteArray* ba ) const;
37 40

  
38 41
  protected:
39 42
    void sendHttpResponse( QByteArray* ba, const QString& format ) const;
src/mapserver/qgsprojectparser.cpp
138 138
  combineExtentAndCrsOfGroupChildren( layerParentElem, doc );
139 139
}
140 140

  
141
void QgsProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const
142
{
143
  QStringList wfsLayersId = wfsLayers();
144

  
145
  if ( mProjectLayerElements.size() < 1 )
146
  {
147
    return;
148
  }
149

  
150
  QMap<QString, QgsMapLayer *> layerMap;
151

  
152
  foreach( const QDomElement &elem, mProjectLayerElements )
153
  {
154
    QString type = elem.attribute( "type" );
155
    if ( type == "vector" )
156
    {
157
      //QgsMapLayer *layer = createLayerFromElement( *layerIt );
158
      QgsMapLayer *layer = createLayerFromElement( elem );
159
      if ( layer && wfsLayersId.contains( layer->id() ) )
160
      {
161
        QgsDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) );
162
        layerMap.insert( layer->id(), layer );
163

  
164
        QDomElement layerElem = doc.createElement( "FeatureType" );
165
        QDomElement nameElem = doc.createElement( "Name" );
166
        //We use the layer name even though it might not be unique.
167
        //Because the id sometimes contains user/pw information and the name is more descriptive
168
        QDomText nameText = doc.createTextNode( layer->name() );
169
        nameElem.appendChild( nameText );
170
        layerElem.appendChild( nameElem );
171

  
172
        QDomElement titleElem = doc.createElement( "Title" );
173
        QDomText titleText = doc.createTextNode( layer->name() );
174
        titleElem.appendChild( titleText );
175
        layerElem.appendChild( titleElem );
176

  
177
        //appendExGeographicBoundingBox( layerElem, doc, layer->extent(), layer->crs() );
178

  
179
        QDomElement srsElem = doc.createElement( "SRS" );
180
        QDomText srsText = doc.createTextNode( layer->crs().authid() );
181
        srsElem.appendChild( srsText );
182
        layerElem.appendChild( srsElem );
183

  
184
        QgsRectangle layerExtent = layer->extent();
185
        QDomElement bBoxElement = doc.createElement( "LatLongBoundingBox" );
186
        bBoxElement.setAttribute( "minx", QString::number( layerExtent.xMinimum() ) );
187
        bBoxElement.setAttribute( "miny", QString::number( layerExtent.yMinimum() ) );
188
        bBoxElement.setAttribute( "maxx", QString::number( layerExtent.xMaximum() ) );
189
        bBoxElement.setAttribute( "maxy", QString::number( layerExtent.yMaximum() ) );
190
        layerElem.appendChild( bBoxElement );
191

  
192
        parentElement.appendChild(layerElem);
193
      }
194
#if QGSMSDEBUG
195
      else
196
      {
197
        QString buf;
198
        QTextStream s( &buf );
199
        layerIt->save( s, 0 );
200
        QgsMSDebugMsg( QString( "layer %1 not found or not in WFS Layers" ).arg( buf ) );
201
      }
202
#endif
203
    }
204
  }
205
  return;
206
}
207

  
141 208
void QgsProjectParser::addLayers( QDomDocument &doc,
142 209
                                  QDomElement &parentElem,
143 210
                                  const QDomElement &legendElem,
......
584 651
  return disabledList;
585 652
}
586 653

  
654
QStringList QgsProjectParser::wfsLayers() const
655
{
656
  QStringList wfsList;
657
  if ( !mXMLDoc )
658
  {
659
    return wfsList;
660
  }
661

  
662
  QDomElement qgisElem = mXMLDoc->documentElement();
663
  if ( qgisElem.isNull() )
664
  {
665
    return wfsList;
666
  }
667
  QDomElement propertiesElem = qgisElem.firstChildElement( "properties" );
668
  if ( propertiesElem.isNull() )
669
  {
670
    return wfsList;
671
  }
672
  QDomElement wfsLayersElem = propertiesElem.firstChildElement( "WFSLayers" );
673
  if ( wfsLayersElem.isNull() )
674
  {
675
    return wfsList;
676
  }
677
  QDomNodeList valueList = wfsLayersElem.elementsByTagName( "value" );
678
  for ( int i = 0; i < valueList.size(); ++i )
679
  {
680
    wfsList << valueList.at( i ).toElement().text();
681
  }
682
  return wfsList;
683
}
684

  
587 685
QStringList QgsProjectParser::supportedOutputCrsList() const
588 686
{
589 687
  QStringList crsList;
src/mapserver/qgsprojectparser.h
38 38
    /**Adds layer and style specific capabilities elements to the parent node. This includes the individual layers and styles, their description, native CRS, bounding boxes, etc.*/
39 39
    virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const;
40 40

  
41
    virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const;
42

  
41 43
    int numberOfLayers() const;
42 44

  
43 45
    /**Returns one or possibly several maplayers for a given layer name and style. If no layers/style are found, an empty list is returned*/
......
58 60
    /**Returns an ID-list of layers which are not queryable (comes from <properties> -> <Identify> -> <disabledLayers in the project file*/
59 61
    virtual QStringList identifyDisabledLayers() const;
60 62

  
63
    /**Returns an ID-list of layers queryable for WFS service (comes from <properties> -> <WFSLayers> in the project file*/
64
    virtual QStringList wfsLayers() const;
65

  
61 66
    /**Returns a set of supported epsg codes for the capabilities document. The list comes from the property <WMSEpsgList> in the project file.
62 67
       An empty set means that all possible CRS should be advertised (which could result in very long capabilities documents)
63 68
       Example:
src/mapserver/qgsrequesthandler.h
41 41
    virtual void sendServiceException( const QgsMapServiceException& ex ) const = 0;
42 42
    virtual void sendGetStyleResponse( const QDomDocument& doc ) const = 0;
43 43
    virtual void sendGetPrintResponse( QByteArray* ba ) const = 0;
44
    virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const = 0;
45
    virtual void sendGetFeatureResponse( QByteArray* ba ) const = 0;
46
    virtual void endGetFeatureResponse( QByteArray* ba ) const = 0;
44 47
    QString format() const { return mFormat; }
45 48
  protected:
46 49
    /**This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
src/mapserver/qgssldparser.h
56 56
    /**Adds layer and style specific capabilities elements to the parent node. This includes the individual layers and styles, their description, native CRS, bounding boxes, etc.*/
57 57
    void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const;
58 58

  
59
    void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const {};
60

  
59 61
    /**Returns number of layers in configuration*/
60 62
    int numberOfLayers() const;
61 63

  
src/mapserver/qgswfsserver.cpp
1
#include "qgswfsserver.h"
2
#include "qgsconfigparser.h"
3
#include "qgscrscache.h"
4
#include "qgsfield.h"
5
#include "qgsgeometry.h"
6
#include "qgsmaplayer.h"
7
#include "qgsmaplayerregistry.h"
8
#include "qgsmaprenderer.h"
9
#include "qgsmaptopixel.h"
10
#include "qgspallabeling.h"
11
#include "qgsproject.h"
12
#include "qgsrasterlayer.h"
13
#include "qgsscalecalculator.h"
14
#include "qgscoordinatereferencesystem.h"
15
#include "qgsvectordataprovider.h"
16
#include "qgsvectorlayer.h"
17
#include "qgsfilter.h"
18
#include "qgslogger.h"
19
#include "qgsmapserviceexception.h"
20
#include "qgssldparser.h"
21
#include "qgssymbol.h"
22
#include "qgssymbolv2.h"
23
#include "qgsrenderer.h"
24
#include "qgslegendmodel.h"
25
#include "qgscomposerlegenditem.h"
26
#include "qgslogger.h"
27
#include "qgsrequesthandler.h"
28
#include <QImage>
29
#include <QPainter>
30
#include <QStringList>
31
#include <QTextStream>
32
#include <QDir>
33

  
34
//for printing
35
#include "qgscomposition.h"
36
#include <QBuffer>
37
#include <QPrinter>
38
#include <QSvgGenerator>
39
#include <QUrl>
40
#include <QPaintEngine>
41

  
42
QgsWFSServer::QgsWFSServer( QMap<QString, QString> parameters )
43
    : mParameterMap( parameters )
44
    , mConfigParser( 0 )
45
{
46
}
47

  
48
QgsWFSServer::~QgsWFSServer()
49
{
50
}
51

  
52
QgsWFSServer::QgsWFSServer()
53
{
54
}
55

  
56
QDomDocument QgsWFSServer::getCapabilities()
57
{
58
  QgsDebugMsg( "Entering." );
59
  QDomDocument doc;
60
  //wfs:WFS_Capabilities element
61
  QDomElement wfsCapabilitiesElement = doc.createElement( "WFS_Capabilities"/*wms:WFS_Capabilities*/ );
62
  wfsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" );
63
  wfsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
64
  wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
65
  wfsCapabilitiesElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
66
  wfsCapabilitiesElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
67
  wfsCapabilitiesElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
68
  wfsCapabilitiesElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
69
  wfsCapabilitiesElement.setAttribute( "version", "1.0.0" );
70
  wfsCapabilitiesElement.setAttribute( "updateSequence", "0" );
71
  doc.appendChild( wfsCapabilitiesElement );
72

  
73
  if ( mConfigParser )
74
  {
75
    mConfigParser->serviceCapabilities( wfsCapabilitiesElement, doc );
76
  }
77

  
78
  //wfs:Capability element
79
  QDomElement capabilityElement = doc.createElement( "Capability"/*wfs:Capability*/ );
80
  wfsCapabilitiesElement.appendChild( capabilityElement );
81
  
82
  //wfs:Request element
83
  QDomElement requestElement = doc.createElement( "Request"/*wfs:Request*/ );
84
  capabilityElement.appendChild( requestElement );
85
  //wfs:GetCapabilities
86
  QDomElement getCapabilitiesElement = doc.createElement( "GetCapabilities"/*wfs:GetCapabilities*/ );
87
  requestElement.appendChild( getCapabilitiesElement );
88
  QDomElement capabilitiesFormatElement = doc.createElement( "Format" );/*wfs:Format*/
89
  getCapabilitiesElement.appendChild( capabilitiesFormatElement );
90
  QDomText capabilitiesFormatText = doc.createTextNode( "text/xml" );
91
  capabilitiesFormatElement.appendChild( capabilitiesFormatText );
92

  
93
  QDomElement dcpTypeElement = doc.createElement( "DCPType"/*wfs:DCPType*/ );
94
  getCapabilitiesElement.appendChild( dcpTypeElement );
95
  QDomElement httpElement = doc.createElement( "HTTP"/*wfs:HTTP*/ );
96
  dcpTypeElement.appendChild( httpElement );
97

  
98
  //Prepare url
99
  //Some client requests already have http://<SERVER_NAME> in the REQUEST_URI variable
100
  QString hrefString;
101
  QString requestUrl = getenv( "REQUEST_URI" );
102
  QUrl mapUrl( requestUrl );
103
  mapUrl.setHost( QString( getenv( "SERVER_NAME" ) ) );
104
  mapUrl.removeQueryItem( "REQUEST" );
105
  mapUrl.removeQueryItem( "VERSION" );
106
  mapUrl.removeQueryItem( "SERVICE" );
107
  hrefString = mapUrl.toString();
108

  
109
  //only Get supported for the moment
110
  QDomElement getElement = doc.createElement( "Get"/*wfs:Get*/ );
111
  httpElement.appendChild( getElement );
112
  QDomElement olResourceElement = doc.createElement( "OnlineResource"/*wfs:OnlineResource*/ );
113
  olResourceElement.setAttribute( "xlink:type", "simple" );
114
  requestUrl.truncate( requestUrl.indexOf( "?" ) + 1 );
115
  olResourceElement.setAttribute( "xlink:href", hrefString );
116
  getElement.appendChild( olResourceElement );
117

  
118
  //wfs:DescribeFeatureType
119
  QDomElement describeFeatureTypeElement = doc.createElement( "DescribeFeatureType"/*wfs:DescribeFeatureType*/ );
120
  requestElement.appendChild( describeFeatureTypeElement );
121
  QDomElement schemaDescriptionLanguageElement = doc.createElement( "SchemaDescriptionLanguage"/*wfs:SchemaDescriptionLanguage*/ );
122
  describeFeatureTypeElement.appendChild( schemaDescriptionLanguageElement );
123
  QDomElement xmlSchemaElement = doc.createElement( "XMLSCHEMA"/*wfs:XMLSCHEMA*/ );
124
  schemaDescriptionLanguageElement.appendChild( xmlSchemaElement );
125
  QDomElement describeFeatureTypeDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
126
  describeFeatureTypeElement.appendChild( describeFeatureTypeDhcTypeElement );
127

  
128
  //wfs:GetFeature
129
  QDomElement getFeatureElement = doc.createElement( "GetFeature"/*wfs:GetFeature*/ );
130
  requestElement.appendChild( getFeatureElement );
131
  QDomElement getFeatureFormatElement = doc.createElement( "ResultFormat" );/*wfs:ResultFormat*/
132
  getFeatureElement.appendChild( getFeatureFormatElement );
133
  QDomElement gmlFormatElement = doc.createElement( "GML2" );/*wfs:GML2*/
134
  getFeatureFormatElement.appendChild( gmlFormatElement );
135
  QDomElement geojsonFormatElement = doc.createElement( "GeoJSON" );/*wfs:GeoJSON*/
136
  getFeatureFormatElement.appendChild( geojsonFormatElement );
137
  QDomElement getFeatureDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
138
  getFeatureElement.appendChild( getFeatureDhcTypeElement );
139

  
140
  //wfs:FeatureTypeList element
141
  QDomElement featureTypeListElement = doc.createElement( "FeatureTypeList"/*wfs:FeatureTypeList*/ );
142
  capabilityElement.appendChild( featureTypeListElement );
143
  //wfs:Operations element
144
  QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ );
145
  featureTypeListElement.appendChild( operationsElement );
146
  //wfs:Query element
147
  QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ );
148
  operationsElement.appendChild( queryElement );
149
  /*
150
   * Adding layer liste in featureTypeListElement
151
   */
152
  if ( mConfigParser )
153
  {
154
    mConfigParser->featureTypeList( featureTypeListElement, doc );
155
  }
156

  
157
  /*
158
   * Adding ogc:Filter_Capabilities in capabilityElement
159
   */
160
  //ogc:Filter_Capabilities element
161
  QDomElement filterCapabilitiesElement = doc.createElement( "ogc:Filter_Capabilities"/*ogc:Filter_Capabilities*/ );
162
  capabilityElement.appendChild( filterCapabilitiesElement );
163
  QDomElement spatialCapabilitiesElement = doc.createElement( "ogc:Spatial_Capabilities"/*ogc:Spatial_Capabilities*/ );
164
  filterCapabilitiesElement.appendChild( spatialCapabilitiesElement );
165
  QDomElement spatialOperatorsElement = doc.createElement( "ogc:Spatial_Operators"/*ogc:Spatial_Operators*/ );
166
  spatialCapabilitiesElement.appendChild( spatialOperatorsElement );
167
  QDomElement ogcBboxElement = doc.createElement( "ogc:BBOX"/*ogc:BBOX*/ );
168
  spatialOperatorsElement.appendChild( ogcBboxElement );
169
  QDomElement scalarCapabilitiesElement = doc.createElement( "ogc:Scalar_Capabilities"/*ogc:Scalar_Capabilities*/ );
170
  filterCapabilitiesElement.appendChild( scalarCapabilitiesElement );
171
  QDomElement comparisonOperatorsElement = doc.createElement( "ogc:Comparison_Operators"/*ogc:Comparison_Operators*/ );
172
  scalarCapabilitiesElement.appendChild( comparisonOperatorsElement );
173
  QDomElement simpleComparisonsElement = doc.createElement( "ogc:Simple_Comparisons"/*ogc:Simple_Comparisons*/ );
174
  comparisonOperatorsElement.appendChild( simpleComparisonsElement );
175
  return doc;
176
}
177

  
178
QDomDocument QgsWFSServer::describeFeatureType()
179
{
180
  QgsDebugMsg( "Entering." );
181
  QDomDocument doc;
182
  //xsd:schema
183
  QDomElement schemaElement = doc.createElement( "schema"/*xsd:schema*/ );
184
  schemaElement.setAttribute( "xmlns", "http://www.w3.org/2001/XMLSchema" );
185
  schemaElement.setAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" );
186
  schemaElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
187
  schemaElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
188
  schemaElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" );
189
  schemaElement.setAttribute( "targetNamespace", "http://www.qgis.org/gml" );
190
  doc.appendChild( schemaElement );
191

  
192
  //xsd:import
193
  QDomElement importElement = doc.createElement( "import"/*xsd:import*/ );
194
  importElement.setAttribute( "namespace", "http://www.opengis.net/gml" );
195
  importElement.setAttribute( "schemaLocation", "http://schemas.opengis.net/gml/2.1.2/feature.xsd" );
196
  schemaElement.appendChild( importElement );
197

  
198
  //read TYPENAME
199
  QString typeName;
200
  QMap<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
201
  if ( type_name_it != mParameterMap.end() )
202
  {
203
    typeName = type_name_it.value();
204
  }
205
  else
206
  {
207
    return doc;
208
  }
209

  
210
  QStringList wfsLayersId = mConfigParser->wfsLayers();
211
  QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
212
  QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
213
  
214
  QList<QgsMapLayer*> layerList;
215
  QgsMapLayer* currentLayer = 0;
216

  
217
  layerList = mConfigParser->mapLayerFromStyle( typeName, "" );
218
  currentLayer = layerList.at( 0 );
219
  
220
  QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
221
  if ( layer && wfsLayersId.contains( layer->id() ) )
222
  {
223
    //is there alias info for this vector layer?
224
    QMap< int, QString > layerAliasInfo;
225
    QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
226
    if ( aliasIt != aliasInfo.constEnd() )
227
    {
228
      layerAliasInfo = aliasIt.value();
229
    }
230

  
231
    //hidden attributes for this layer
232
    QSet<QString> layerHiddenAttributes;
233
    QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
234
    if ( hiddenIt != hiddenAttributes.constEnd() )
235
    {
236
      layerHiddenAttributes = hiddenIt.value();
237
    }
238
    
239
    //do a select with searchRect and go through all the features
240
    QgsVectorDataProvider* provider = layer->dataProvider();
241
    if ( !provider )
242
    {
243
      return doc;
244
    }
245

  
246
    typeName = typeName.replace( QString(" "), QString("_") );
247
    
248
    //xsd:element
249
    QDomElement elementElem = doc.createElement( "element"/*xsd:element*/ );
250
    elementElem.setAttribute( "name", typeName );
251
    elementElem.setAttribute( "type", "qgs:" + typeName + "Type" );
252
    elementElem.setAttribute( "substitutionGroup", "gml:_Feature" );
253
    schemaElement.appendChild( elementElem );
254

  
255
    //xsd:complexType
256
    QDomElement complexTypeElem = doc.createElement( "complexType"/*xsd:complexType*/ );
257
    complexTypeElem.setAttribute( "name", typeName + "Type" );
258
    schemaElement.appendChild( complexTypeElem );
259

  
260
    //xsd:complexType
261
    QDomElement complexContentElem = doc.createElement( "complexContent"/*xsd:complexContent*/ );
262
    complexTypeElem.appendChild( complexContentElem );
263

  
264
    //xsd:extension
265
    QDomElement extensionElem = doc.createElement( "extension"/*xsd:extension*/ );
266
    extensionElem.setAttribute( "base", "gml:AbstractFeatureType" );
267
    complexContentElem.appendChild( extensionElem );
268

  
269
    //xsd:sequence
270
    QDomElement sequenceElem = doc.createElement( "sequence"/*xsd:sequence*/ );
271
    extensionElem.appendChild( sequenceElem );
272

  
273
    //xsd:element
274
    QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
275
    geomElem.setAttribute( "name", "geometry" );
276
    geomElem.setAttribute( "type", "gml:GeometryPropertyType" );
277
    geomElem.setAttribute( "minOccurs", "0" );
278
    geomElem.setAttribute( "maxOccurs", "1" );
279
    sequenceElem.appendChild( geomElem );
280

  
281
    const QgsFieldMap& fields = provider->fields();
282
    for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
283
    {
284

  
285
      QString attributeName = it.value().name();
286
      //skip attribute if it has edit type 'hidden'
287
      if ( layerHiddenAttributes.contains( attributeName ) )
288
      {
289
        continue;
290
      }
291

  
292
      //xsd:element
293
      QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
294
      geomElem.setAttribute( "name", attributeName );
295
      if ( it.value().type() == 2 )
296
        geomElem.setAttribute( "type", "integer" );
297
      else if ( it.value().type() == 6 )
298
        geomElem.setAttribute( "type", "double" );
299
      else
300
        geomElem.setAttribute( "type", "string" );
301

  
302
      sequenceElem.appendChild( geomElem );
303

  
304
      //check if the attribute name should be replaced with an alias
305
      QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
306
      if ( aliasIt != layerAliasInfo.constEnd() )
307
      {
308
        geomElem.setAttribute( "alias", aliasIt.value() );
309
      }
310

  
311
    }
312
  }
313

  
314
  return doc;
315
}
316

  
317
int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format )
318
{
319
  QgsDebugMsg( "Info format is:" + infoFormat );
320

  
321
  //read TYPENAME
322
  QMap<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
323
  if ( type_name_it != mParameterMap.end() )
324
  {
325
    mTypeName = type_name_it.value();
326
  }
327
  else
328
  {
329
    return 1;
330
  }
331

  
332
  QStringList wfsLayersId = mConfigParser->wfsLayers();
333
  QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
334
  QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
335
  
336
  QList<QgsMapLayer*> layerList;
337
  QgsMapLayer* currentLayer = 0;
338

  
339
  layerList = mConfigParser->mapLayerFromStyle( mTypeName, "" );
340
  currentLayer = layerList.at( 0 );
341
  
342
  QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
343
  if ( layer && wfsLayersId.contains( layer->id() ) )
344
  {
345
    //is there alias info for this vector layer?
346
    QMap< int, QString > layerAliasInfo;
347
    QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
348
    if ( aliasIt != aliasInfo.constEnd() )
349
    {
350
      layerAliasInfo = aliasIt.value();
351
    }
352

  
353
    //hidden attributes for this layer
354
    QSet<QString> layerHiddenAttributes;
355
    QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
356
    if ( hiddenIt != hiddenAttributes.constEnd() )
357
    {
358
      layerHiddenAttributes = hiddenIt.value();
359
    }
360
    
361
    //do a select with searchRect and go through all the features
362
    QgsVectorDataProvider* provider = layer->dataProvider();
363
    if ( !provider )
364
    {
365
      return 2;
366
    }
367

  
368
    QgsFeature feature;
369
    QgsAttributeMap featureAttributes;
370
    const QgsFieldMap& fields = provider->fields();
371

  
372
    //map extent
373
    QgsRectangle searchRect = layer->extent();
374

  
375
    //read FEATUREDID
376
    bool fidOk = false;
377
    QString fid;
378
    QMap<QString, QString>::const_iterator fidIt = mParameterMap.find( "FEATUREID" );
379
    if ( fidIt != mParameterMap.end() ) {
380
      fidOk = true;
381
      fid = fidIt.value();
382
    }
383

  
384
    //read FILTER
385
    bool filterOk = false;
386
    QDomDocument filter;
387
    QMap<QString, QString>::const_iterator filterIt = mParameterMap.find( "FILTER" );
388
    if ( filterIt != mParameterMap.end() ) {
389
      try {
390
      QString errorMsg;
391
      if ( !filter.setContent( filterIt.value(), true, &errorMsg ) )
392
      {
393
        QgsDebugMsg( "soap request parse error" );
394
        QgsDebugMsg( "error message: " + errorMsg );
395
        QgsDebugMsg( "the xml string was:" );
396
        QgsDebugMsg( filterIt.value() );
397
      }
398
      else 
399
      {
400
        filterOk = true;
401
      }
402
      } catch(QgsMapServiceException& e ) {
403
        filterOk = false;
404
      }
405
    }
406

  
407

  
408
    bool conversionSuccess;
409
    double minx, miny, maxx, maxy;
410
    bool bboxOk = false;
411
    //read BBOX
412
    QMap<QString, QString>::const_iterator bbIt = mParameterMap.find( "BBOX" );
413
    if ( bbIt == mParameterMap.end() )
414
    {
415
      minx = 0; miny = 0; maxx = 0; maxy = 0;
416
    }
417
    else
418
    {
419
      bboxOk = true;
420
      QString bbString = bbIt.value();
421
      minx = bbString.section( ",", 0, 0 ).toDouble( &conversionSuccess );
422
      if ( !conversionSuccess ) {bboxOk = false;}
423
      miny = bbString.section( ",", 1, 1 ).toDouble( &conversionSuccess );
424
      if ( !conversionSuccess ) {bboxOk = false;}
425
      maxx = bbString.section( ",", 2, 2 ).toDouble( &conversionSuccess );
426
      if ( !conversionSuccess ) {bboxOk = false;}
427
      maxy = bbString.section( ",", 3, 3 ).toDouble( &conversionSuccess );
428
      if ( !conversionSuccess ) {bboxOk = false;}
429
    }
430

  
431
    //read MAXFEATURES
432
    long maxFeat = layer->featureCount();
433
    long featureCounter = 0;
434
    QMap<QString, QString>::const_iterator mfIt = mParameterMap.find( "MAXFEATURES" );
435
    if ( mfIt != mParameterMap.end() )
436
    {
437
       QString mfString = mfIt.value();
438
       bool mfOk;
439
       maxFeat = mfString.toLong(&mfOk, 10);
440
       if ( !mfOk ) { maxFeat = layer->featureCount(); }
441
    }
442

  
443
    //read PROPERTYNAME
444
    mWithGeom = true;
445
    QgsAttributeList attrIndexes = provider->attributeIndexes();
446
    QMap<QString, QString>::const_iterator pnIt = mParameterMap.find( "PROPERTYNAME" );
447
    if ( pnIt != mParameterMap.end() )
448
    {
449
       QStringList attrList = pnIt.value().split( "," );
450
       if ( attrList.size() > 0 )
451
       {
452
         mWithGeom = false;
453
         QStringList::const_iterator alstIt;
454
         QList<int> idxList;
455
         QMap<QString, int> fieldMap = provider->fieldNameMap();
456
         QMap<QString, int>::const_iterator fieldIt;
457
         QString fieldName;
458
         for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt )
459
         {
460
           fieldName = *alstIt;
461
           fieldIt = fieldMap.find( fieldName );
462
           if ( fieldIt != fieldMap.end() )
463
           {
464
             idxList.append( fieldIt.value() );
465
           }
466
           else if ( fieldName == "geometry" )
467
           {
468
             mWithGeom = true;
469
           }
470
         }
471
         if ( idxList.size() > 0 || mWithGeom)
472
         {
473
           attrIndexes = idxList;
474
         }
475
         else
476
         {
477
           mWithGeom = true;
478
         }
479
       }
480
    }
481
    
482
    QgsCoordinateReferenceSystem layerCrs = layer->crs();
483
    
484
    startGetFeature( request, format );
485

  
486
    if ( fidOk )
487
    {
488
      provider->featureAtId(  fid.toInt(), feature, mWithGeom, attrIndexes );
489
      sendGetFeature( request, format, &feature, 0, layerCrs, fields, layerHiddenAttributes);
490
    }
491
    else if ( filterOk )
492
    {
493
      provider->select( attrIndexes, searchRect, mWithGeom, true );
494
      try {
495
        QgsFilter* mFilter = QgsFilter::createFilterFromXml( filter.firstChild().toElement().firstChild().toElement(), layer );
496
        while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
497
        {
498
          if ( mFilter )
499
          {
500
            if ( mFilter->evaluate( feature ) )
501
            {
502
              sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes);
503
              ++featureCounter;
504
            }
505
          }
506
          else
507
          {
508
            sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes);
509
            ++featureCounter;
510
          }
511
        }
512
        delete mFilter;
513
      } catch(QgsMapServiceException& e ) {
514
        while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
515
        {
516
          sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes);
517
          ++featureCounter;
518
        }
519
      }
520
    }
521
    else
522
    {
523
      if ( bboxOk )
524
        searchRect.set( minx, miny, maxx, maxy );
525
      provider->select( attrIndexes, searchRect, mWithGeom, true );
526
      while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
527
      {
528
        sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes);
529
        ++featureCounter;
530
      }
531
    }
532
   
533
    endGetFeature( request, format );
534
  }
535
  else
536
  {
537
    return 2;
538
  }
539
  return 0;
540
}
541

  
542
void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& format ) 
543
{
544
  QByteArray result;
545
  QString fcString;
546
  if ( format == "GeoJSON" )
547
  {
548
    fcString = "{\"type\": \"FeatureCollection\",\n";
549
    fcString += " \"features\": [\n";
550
    result = fcString.toUtf8();
551
    request.startGetFeatureResponse(&result, format);
552
  }
553
  else
554
  {
555
    //wfs:FeatureCollection
556
    fcString = "<wfs:FeatureCollection";
557
    fcString += " xmlns=\"http://www.opengis.net/wfs\"";
558
    fcString += " xmlns:wfs=\"http://www.opengis.net/wfs\"";
559
    fcString += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
560
    fcString += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd\"";
561
    fcString += " xmlns:ogc=\"http://www.opengis.net/ogc\"";
562
    fcString += " xmlns:gml=\"http://www.opengis.net/gml\"";
563
    fcString += " xmlns:ows=\"http://www.opengis.net/ows\"";
564
    fcString += " xmlns:xlink=\"http://www.w3.org/1999/xlink\"";
565
    fcString += " xmlns:qgs=\"http://www.qgis.org/gml\"";
566
    fcString += ">";
567
    result = fcString.toUtf8();
568
    request.startGetFeatureResponse(&result, format);
569
  }
570
  fcString = "";
571
}
572

  
573
void QgsWFSServer::sendGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes) /*const*/
574
{
575
  QByteArray result;
576
  if ( format == "GeoJSON" )
577
  {
578
    QString fcString;
579
    if (featIdx == 0)
580
      fcString += "  ";
581
    else
582
      fcString += " ,";
583
    fcString += createFeatureGeoJSON(feat, crs, fields, hiddenAttributes);
584
    fcString += "\n";
585

  
586
    result = fcString.toUtf8();
587
    request.sendGetFeatureResponse( &result );
588
    fcString = "";
589
  }
590
  else
591
  {
592
    QDomDocument gmlDoc;
593
    QDomElement featureElement = createFeatureElem(feat, gmlDoc, crs, fields, hiddenAttributes);
594
    gmlDoc.appendChild(featureElement);
595

  
596
    result = gmlDoc.toByteArray();
597
    request.sendGetFeatureResponse( &result );
598
    gmlDoc.removeChild(featureElement);
599
  }
600
}
601

  
602
void QgsWFSServer::endGetFeature( QgsRequestHandler& request, const QString& format ) 
603
{
604
  QByteArray result;
605
  QString fcString;
606
  if ( format == "GeoJSON" )
607
  {
608
    fcString += " ]\n";
609
    fcString += "}";
610

  
611
    result = fcString.toUtf8();
612
    request.endGetFeatureResponse( &result );
613
    fcString = "";
614
  }
615
  else
616
  {
617
    fcString = "</wfs:FeatureCollection>";
618
    result = fcString.toUtf8();
619
    request.endGetFeatureResponse( &result );
620
    fcString = "";
621
  }
622
}
623

  
624
QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes) /*const*/
625
{
626
  QString fStr = "{\"type\": \"Feature\",\n";
627

  
628
  fStr += "   \"id\": ";
629
  fStr +=  QString::number( feat->id() );
630
  fStr += ",\n";
631

  
632
  QgsGeometry* geom = feat->geometry();
633
  if ( geom && mWithGeom )
634
  {
635
    fStr += "  \"geometry\": ";
636
    fStr += geom->exportToGeoJSON();
637
    fStr += ",\n";
638
  }
639

  
640
  //read all attribute values from the feature
641
  fStr += "   \"properties\": {\n";
642
  QgsAttributeMap featureAttributes = feat->attributeMap();
643
  int attributeCounter = 0;
644
  for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
645
  {
646
    QString attributeName = fields[it.key()].name();
647
    //skip attribute if it has edit type 'hidden'
648
    if ( hiddenAttributes.contains( attributeName ) )
649
    {
650
      continue;
651
    }
652

  
653
    if (attributeCounter == 0)
654
      fStr += "    \"";
655
    else
656
      fStr += "   ,\"";
657
    fStr += attributeName;
658
    fStr += "\": ";
659
    if (it->type() == 6 || it->type() == 2) 
660
    {
... This diff was truncated because it exceeds the maximum size that can be displayed.