675 changes: 675 additions & 0 deletions images/themes/gis/mIconOws.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/gis/mIconVectorLayer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
237 changes: 237 additions & 0 deletions images/themes/gis/mIconVectorLayer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/gis/mIconWcs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ void QgisApp::createActions()
connect( mActionAddSpatiaLiteLayer, SIGNAL( triggered() ), this, SLOT( addSpatiaLiteLayer() ) );
connect( mActionAddMssqlLayer, SIGNAL( triggered() ), this, SLOT( addMssqlLayer() ) );
connect( mActionAddWmsLayer, SIGNAL( triggered() ), this, SLOT( addWmsLayer() ) );
connect( mActionAddWcsLayer, SIGNAL( triggered() ), this, SLOT( addWcsLayer() ) );
connect( mActionAddWfsLayer, SIGNAL( triggered() ), this, SLOT( addWfsLayer() ) );
connect( mActionOpenTable, SIGNAL( triggered() ), this, SLOT( attributeTable() ) );
connect( mActionToggleEditing, SIGNAL( triggered() ), this, SLOT( toggleEditing() ) );
Expand Down Expand Up @@ -1595,6 +1596,7 @@ void QgisApp::setTheme( QString theThemeName )
mActionNewBookmark->setIcon( getThemeIcon( "/mActionNewBookmark.png" ) );
mActionCustomProjection->setIcon( getThemeIcon( "/mActionCustomProjection.png" ) );
mActionAddWmsLayer->setIcon( getThemeIcon( "/mActionAddWmsLayer.png" ) );
mActionAddWcsLayer->setIcon( getThemeIcon( "/mActionAddWcsLayer.png" ) );
mActionAddWfsLayer->setIcon( getThemeIcon( "/mActionAddWfsLayer.png" ) );
mActionAddToOverview->setIcon( getThemeIcon( "/mActionInOverview.png" ) );
mActionAnnotation->setIcon( getThemeIcon( "/mActionAnnotation.png" ) );
Expand Down Expand Up @@ -2638,6 +2640,27 @@ void QgisApp::addWmsLayer()
delete wmss;
}

void QgisApp::addWcsLayer()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
QgsDebugMsg( "about to addWcsLayer" );

// TODO: QDialog for now, switch to QWidget in future
QDialog *wcss = dynamic_cast<QDialog*>( QgsProviderRegistry::instance()->selectWidget( QString( "gdal" ), this ) );
if ( !wcss )
{
QMessageBox::warning( this, tr( "WCS" ), tr( "Cannot get WCS select dialog from provider." ) );
return;
}
connect( wcss , SIGNAL( addRasterLayer( QString const &, QString const &, QString const & ) ),
this , SLOT( addRasterLayer( QString const &, QString const &, QString const & ) ) );
wcss->exec();
delete wcss;
}

void QgisApp::addWfsLayer()
{
if ( !mMapCanvas )
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionAddPgLayer() { return mActionAddPgLayer; }
QAction *actionAddSpatiaLiteLayer() { return mActionAddSpatiaLiteLayer; };
QAction *actionAddWmsLayer() { return mActionAddWmsLayer; }
QAction *actionAddWcsLayer() { return mActionAddWcsLayer; }
QAction *actionAddWfsLayer() { return mActionAddWfsLayer; }
QAction *actionOpenTable() { return mActionOpenTable; }
QAction *actionToggleEditing() { return mActionToggleEditing; }
Expand Down Expand Up @@ -771,6 +772,8 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
void fileExit();
//! Add a WMS layer to the map
void addWmsLayer();
//! Add a WCS layer to the map
void addWcsLayer();
//! Add a WFS layer to the map
void addWfsLayer();
//! Set map tool to Zoom out
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ SET(QGIS_CORE_SRCS
qgsmessagelog.cpp
qgscredentials.cpp
qgsoverlayobject.cpp
qgsowsconnection.cpp
qgspalgeometry.cpp
qgspallabeling.cpp
qgspalobjectpositionmanager.cpp
Expand Down Expand Up @@ -337,6 +338,7 @@ SET(QGIS_CORE_HDRS
qgsmimedatautils.h
qgscredentials.h
qgsoverlayobjectpositionmanager.h
qgsowsconnection.h
qgspallabeling.h
qgspalobjectpositionmanager.h
qgspluginlayer.h
Expand Down
34 changes: 32 additions & 2 deletions src/core/qgsdataitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,16 @@ const QIcon &QgsZipItem::iconZip()


QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path )
: QObject( parent ), mType( type ), mParent( parent ), mPopulated( false ), mName( name ), mPath( path )
// Do not pass parent to QObject, Qt would delete this when parent is deleted
: QObject(), mType( type ), mParent( parent ), mPopulated( false ), mName( name ), mPath( path )
{
}

QgsDataItem::~QgsDataItem()
{
QgsDebugMsg( "mName = " + mName + " mPath = " + mPath);
}

// TODO: This is copy from QgisApp, bad
// TODO: add some caching mechanism ?
QPixmap QgsDataItem::getThemePixmap( const QString theName )
Expand Down Expand Up @@ -282,6 +288,26 @@ void QgsDataItem::deleteChildItem( QgsDataItem * child )
emit endRemoveItems();
}

QgsDataItem * QgsDataItem::removeChildItem( QgsDataItem * child )
{
QgsDebugMsg( "mName = " + child->mName );
int i = mChildren.indexOf( child );
Q_ASSERT( i >= 0 );
emit beginRemoveItems( this, i, i );
mChildren.remove( i );
emit endRemoveItems();
disconnect( child, SIGNAL( beginInsertItems( QgsDataItem*, int, int ) ),
this, SLOT( emitBeginInsertItems( QgsDataItem*, int, int ) ) );
disconnect( child, SIGNAL( endInsertItems() ),
this, SLOT( emitEndInsertItems() ) );
disconnect( child, SIGNAL( beginRemoveItems( QgsDataItem*, int, int ) ),
this, SLOT( emitBeginRemoveItems( QgsDataItem*, int, int ) ) );
disconnect( child, SIGNAL( endRemoveItems() ),
this, SLOT( emitEndRemoveItems() ) );
child->setParent(0);
return child;
}

int QgsDataItem::findItem( QVector<QgsDataItem*> items, QgsDataItem * item )
{
for ( int i = 0; i < items.size(); i++ )
Expand Down Expand Up @@ -388,8 +414,12 @@ QgsDataCollectionItem::QgsDataCollectionItem( QgsDataItem* parent, QString name,

QgsDataCollectionItem::~QgsDataCollectionItem()
{
QgsDebugMsg( "Entered");
foreach( QgsDataItem* i, mChildren )
delete i;
{
QgsDebugMsg( QString("delete child = 0x%0").arg((qlonglong)i,8,16,QLatin1Char('0')) );
delete i;
}
}

//-----------------------------------------------------------------------
Expand Down
7 changes: 6 additions & 1 deletion src/core/qgsdataitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class CORE_EXPORT QgsDataItem : public QObject
};

QgsDataItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path );
virtual ~QgsDataItem() {}
virtual ~QgsDataItem();

bool hasChildren();

Expand All @@ -74,6 +74,10 @@ class CORE_EXPORT QgsDataItem : public QObject
// remove and delete child item, signals to browser are emited
virtual void deleteChildItem( QgsDataItem * child );

// remove child item but don't delete it, signals to browser are emited
// returns pointer to the removed item or null if no such item was found
virtual QgsDataItem * removeChildItem( QgsDataItem * child );

virtual bool equal( const QgsDataItem *other );

virtual QWidget * paramWidget() { return 0; }
Expand Down Expand Up @@ -112,6 +116,7 @@ class CORE_EXPORT QgsDataItem : public QObject

Type type() const { return mType; }
QgsDataItem* parent() const { return mParent; }
void setParent( QgsDataItem* parent ) { mParent = parent; }
QVector<QgsDataItem*> children() const { return mChildren; }
QIcon icon() const { return mIcon; }
QString name() const { return mName; }
Expand Down
181 changes: 181 additions & 0 deletions src/core/qgsowsconnection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/***************************************************************************
qgsowsconnection.cpp - selector for WMS servers, etc.
-------------------
begin : 3 April 2005
copyright :
original : (C) 2005 by Brendan Morley email : morb at ozemail dot com dot au
wms search : (C) 2009 Mathias Walker <mwa at sourcepole.ch>, Sourcepole AG
wms-c support : (C) 2010 Juergen E. Fischer < jef at norbit dot de >, norBIT GmbH
generalized : (C) 2012 Radim Blazek, based on qgswmsconnection.cpp
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

//#include "../providers/wms/qgswmsprovider.h"
#include "qgis.h" // GEO_EPSG_CRS_ID
//#include "qgisapp.h" //for getThemeIcon
//#include "qgscontexthelp.h"
//#include "qgscoordinatereferencesystem.h"
#include "qgsdatasourceuri.h"
//#include "qgsgenericprojectionselector.h"
#include "qgslogger.h"
//#include "qgsmanageconnectionsdialog.h"
//#include "qgsmessageviewer.h"
//#include "qgsnewhttpconnection.h"
//#include "qgsnumericsortlistviewitem.h"
#include "qgsproject.h"
#include "qgsproviderregistry.h"
#include "qgsowsconnection.h"
//#include "qgsnetworkaccessmanager.h"

//#include <QButtonGroup>
//#include <QFileDialog>
//#include <QRadioButton>
//#include <QDomDocument>
//#include <QHeaderView>
//#include <QImageReader>
#include <QInputDialog>
//#include <QMap>
#include <QMessageBox>
#include <QPicture>
#include <QSettings>
#include <QUrl>

#include <QNetworkRequest>
#include <QNetworkReply>

QgsOWSConnection::QgsOWSConnection( const QString & theService, const QString & theConnName ) :
mConnName( theConnName ),
mService( theService )
{
QgsDebugMsg( "theConnName = " + theConnName );

QSettings settings;

// WMS (providers/wfs/qgswmsconnection.cpp):
//QString key = "/Qgis/connections-wms/" + mConnName;
//QString credentialsKey = "/Qgis/WMS/" + mConnName;

// WFS (providers/wfs/qgswfsconnection.cpp):
//QString key = "/Qgis/connections-wfs/" + mConnName + "/url";

// WCS - there was no WCS before

QString key = "/Qgis/connections-" + mService.toLower() + "/" + mConnName;
QString credentialsKey = "/Qgis/" + mService + "/" + mConnName;

QStringList connStringParts;

mConnectionInfo = settings.value( key + "/url" ).toString();
mUri.setParam( "url", settings.value( key + "/url" ).toString() );

// Check for credentials and prepend to the connection info
QString username = settings.value( credentialsKey + "/username" ).toString();
QString password = settings.value( credentialsKey + "/password" ).toString();
if ( !username.isEmpty() )
{
// check for a password, if none prompt to get it
if ( password.isEmpty() )
{
//password = QInputDialog::getText( this, tr( "WMS Password for %1" ).arg( theConnName ), "Password", QLineEdit::Password );
password = QInputDialog::getText( 0, tr( "WMS Password for %1" ).arg( mConnName ), "Password", QLineEdit::Password );
}
mConnectionInfo = "username=" + username + ",password=" + password + ",url=" + mConnectionInfo;
mUri.setParam( "username", username );
mUri.setParam( "password", password );
}

bool ignoreGetMap = settings.value( key + "/ignoreGetMapURI", false ).toBool();
bool ignoreGetFeatureInfo = settings.value( key + "/ignoreGetFeatureInfoURI", false ).toBool();
bool ignoreAxisOrientation = settings.value( key + "/ignoreAxisOrientation", false ).toBool();
bool invertAxisOrientation = settings.value( key + "/invertAxisOrientation", false ).toBool();
if ( ignoreGetMap )
{
mUri.setParam( "IgnoreGetMapUrl", "1" );
}
if ( ignoreGetFeatureInfo )
{
mUri.setParam( "IgnoreGetFeatureInfoUrl", "1" );
}
if ( ignoreAxisOrientation )
{
mUri.setParam( "IgnoreAxisOrientation", "1" );
}
if ( invertAxisOrientation )
{
mUri.setParam( "InvertAxisOrientation", "1" );
}

QgsDebugMsg( QString( "Connection info: '%1'." ).arg( mConnectionInfo ) );
}

QgsOWSConnection::~QgsOWSConnection()
{

}

QString QgsOWSConnection::connectionInfo( )
{
return mConnectionInfo;
}

QgsDataSourceURI QgsOWSConnection::uri()
{
return mUri;
}
/*
QgsDataProvider * QgsOWSConnection::provider( )
{
// TODO: remove completely from this class?
// load the server data provider plugin
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
//QMap<QString,QString> keys;
QgsDataProvider *provider =
( QgsDataProvider* ) pReg->provider( "wms", mUri.encodedUri() );
return provider;
}
*/


QStringList QgsOWSConnection::connectionList( const QString & theService )
{
QSettings settings;
//settings.beginGroup( "/Qgis/connections-wms" );
settings.beginGroup( "/Qgis/connections-" + theService.toLower() );
return settings.childGroups();
}

QString QgsOWSConnection::selectedConnection( const QString & theService )
{
QSettings settings;
//return settings.value( "/Qgis/connections-wms/selected" ).toString();
return settings.value( "/Qgis/connections-" + theService.toLower() + "/selected" ).toString();
}

void QgsOWSConnection::setSelectedConnection( const QString & theService, const QString & name )
{
QSettings settings;
//settings.setValue( "/Qgis/connections-wms/selected", name );
settings.setValue( "/Qgis/connections-" + theService.toLower() + "/selected", name );
}

void QgsOWSConnection::deleteConnection( const QString & theService, const QString & name )
{
QSettings settings;
//settings.remove( "/Qgis/connections-wms/" + name );
//settings.remove( "/Qgis/WMS/" + name );
settings.remove( "/Qgis/connections-" + theService.toLower() + "/" + name );
settings.remove( "/Qgis/" + theService + "/" + name );
}
75 changes: 75 additions & 0 deletions src/core/qgsowsconnection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/***************************************************************************
qgsowsconnection.h - OWS connection
-------------------
begin : 3 April 2005
original : (C) 2005 by Brendan Morley email : morb at ozemail dot com dot au
wms search : (C) 2009 Mathias Walker <mwa at sourcepole.ch>, Sourcepole AG
generalized : (C) 2012 Radim Blazek, based on qgswmsconnection.h
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSOWSCONNECTION_H
#define QGSOWSCONNECTION_H
#include "qgsdatasourceuri.h"
//#include "qgisgui.h"
//#include "qgscontexthelp.h"

#include <QStringList>
#include <QPushButton>

class QgisApp;
//class QgsDataProvider;
class QgsDataProvider;
/*class QButtonGroup;*/
/*class QgsNumericSortTreeWidgetItem;*/
class QDomDocument;
class QDomElement;

/*!
* \brief Connections management
*/
class QgsOWSConnection : public QObject
{
// Q_OBJECT

public:
/**
* Constructor
* @param theService service name: WMS,WFS,WCS
*/
QgsOWSConnection( const QString & theService, const QString & theConnName );
//! Destructor
~QgsOWSConnection();

static QStringList connectionList( const QString & theService );

static void deleteConnection( const QString & theService, const QString & name );

static QString selectedConnection( const QString & theService );
static void setSelectedConnection( const QString & theService, const QString & name );


public:
//QgsDataProvider *provider();
QString connectionInfo();
QString mConnName;
QString mConnectionInfo;
QgsDataSourceURI uri();
private:
QgsDataSourceURI mUri;
QString mService;
};


#endif // QGSOWSCONNECTION_H
4 changes: 4 additions & 0 deletions src/core/raster/qgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2312,6 +2312,10 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
{
return;
}
if ( !mDataProvider->isValid() )
{
return;
}

if ( provider == "gdal" )
{
Expand Down
4 changes: 4 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ qgsnewhttpconnection.cpp
qgsnewvectorlayerdialog.cpp
qgsnumericsortlistviewitem.cpp
qgscredentialdialog.cpp
qgsowssourceselect.cpp
qgsprojectbadlayerguihandler.cpp
qgsprojectionselector.cpp
qgsquickprint.cpp
Expand Down Expand Up @@ -147,6 +148,7 @@ qgsmessagelogviewer.h
qgsnewhttpconnection.h
qgsnewvectorlayerdialog.h
qgscredentialdialog.h
qgsowssourceselect.h
qgsprojectionselector.h
qgsquickprint.h
qgsludialog.h
Expand Down Expand Up @@ -182,6 +184,7 @@ qgsmaptoolpan.h
qgsmaptoolzoom.h
qgsmessageviewer.h
qgscredentialdialog.h
qgsowssourceselect.h
qgsprojectionselector.h
qgsrubberband.h
qgsvertexmarker.h
Expand Down Expand Up @@ -214,6 +217,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsdetaileditemwidgetbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsgenericprojectionselectorbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsmessageviewer.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsmessagelogviewer.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsowssourceselectbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgscredentialdialog.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsprojectionselectorbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsquerybuilderbase.h
Expand Down
56 changes: 39 additions & 17 deletions src/gui/qgsmanageconnectionsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void QgsManageConnectionsDialog::doExportImport()
switch ( mConnectionType )
{
case WMS:
doc = saveWMSConnections( items );
doc = saveOWSConnections( items, "WMS" );
break;
case WFS:
doc = saveWFSConnections( items );
Expand All @@ -111,6 +111,9 @@ void QgsManageConnectionsDialog::doExportImport()
case MSSQL:
doc = saveMssqlConnections( items );
break;
case WCS:
doc = saveOWSConnections( items, "WCS" );
break;
}

QFile file( mFileName );
Expand Down Expand Up @@ -156,7 +159,7 @@ void QgsManageConnectionsDialog::doExportImport()
switch ( mConnectionType )
{
case WMS:
loadWMSConnections( doc, items );
loadOWSConnections( doc, items, "WMS" );
break;
case WFS:
loadWFSConnections( doc, items );
Expand All @@ -167,6 +170,9 @@ void QgsManageConnectionsDialog::doExportImport()
case MSSQL:
loadMssqlConnections( doc, items );
break;
case WCS:
loadOWSConnections( doc, items, "WCS" );
break;
}
// clear connections list and close window
listConnections->clear();
Expand All @@ -190,6 +196,9 @@ bool QgsManageConnectionsDialog::populateConnections()
case WFS:
settings.beginGroup( "/Qgis/connections-wfs" );
break;
case WCS:
settings.beginGroup( "/Qgis/connections-wcs" );
break;
case PostGIS:
settings.beginGroup( "/PostgreSQL/connections" );
break;
Expand Down Expand Up @@ -257,6 +266,15 @@ bool QgsManageConnectionsDialog::populateConnections()
}
break;

case WCS:
if ( root.tagName() != "qgsWCSConnections" )
{
QMessageBox::information( this, tr( "Loading connections" ),
tr( "The file is not an WCS connections exchange file." ) );
return false;
}
break;

case PostGIS:
if ( root.tagName() != "qgsPgConnections" )
{
Expand Down Expand Up @@ -288,27 +306,31 @@ bool QgsManageConnectionsDialog::populateConnections()
return true;
}

QDomDocument QgsManageConnectionsDialog::saveWMSConnections( const QStringList &connections )
QDomDocument QgsManageConnectionsDialog::saveOWSConnections( const QStringList &connections, const QString & service )
{
QDomDocument doc( "connections" );
QDomElement root = doc.createElement( "qgsWMSConnections" );
QDomElement root = doc.createElement( "qgs" + service.toUpper() + "Connections" );
root.setAttribute( "version", "1.0" );
doc.appendChild( root );

QSettings settings;
QString path;
for ( int i = 0; i < connections.count(); ++i )
{
path = "/Qgis/connections-wms/";
QDomElement el = doc.createElement( "wms" );
path = "/Qgis/connections-" + service.toLower() + "/";
QDomElement el = doc.createElement( service.toLower() );
el.setAttribute( "name", connections[ i ] );
el.setAttribute( "url", settings.value( path + connections[ i ] + "/url", "" ).toString() );
el.setAttribute( "ignoreGetMapURI", settings.value( path + connections[i] + "/ignoreGetMapURI", false ).toBool() ? "true" : "false" );
el.setAttribute( "ignoreGetFeatureInfoURI", settings.value( path + connections[i] + "/ignoreGetFeatureInfoURI", false ).toBool() ? "true" : "false" );
el.setAttribute( "ignoreAxisOrientation", settings.value( path + connections[i] + "/ignoreAxisOrientation", false ).toBool() ? "true" : "false" );
el.setAttribute( "invertAxisOrientation", settings.value( path + connections[i] + "/invertAxisOrientation", false ).toBool() ? "true" : "false" );

path = "/Qgis/WMS/";
if ( service == "WMS" )
{
el.setAttribute( "ignoreGetMapURI", settings.value( path + connections[i] + "/ignoreGetMapURI", false ).toBool() ? "true" : "false" );
el.setAttribute( "ignoreGetFeatureInfoURI", settings.value( path + connections[i] + "/ignoreGetFeatureInfoURI", false ).toBool() ? "true" : "false" );
el.setAttribute( "ignoreAxisOrientation", settings.value( path + connections[i] + "/ignoreAxisOrientation", false ).toBool() ? "true" : "false" );
el.setAttribute( "invertAxisOrientation", settings.value( path + connections[i] + "/invertAxisOrientation", false ).toBool() ? "true" : "false" );
}

path = "/Qgis/" + service.toUpper() + "/";
el.setAttribute( "username", settings.value( path + connections[ i ] + "/username", "" ).toString() );
el.setAttribute( "password", settings.value( path + connections[ i ] + "/password", "" ).toString() );
root.appendChild( el );
Expand Down Expand Up @@ -424,19 +446,19 @@ QDomDocument QgsManageConnectionsDialog::saveMssqlConnections( const QStringList
return doc;
}

void QgsManageConnectionsDialog::loadWMSConnections( const QDomDocument &doc, const QStringList &items )
void QgsManageConnectionsDialog::loadOWSConnections( const QDomDocument &doc, const QStringList &items, const QString &service )
{
QDomElement root = doc.documentElement();
if ( root.tagName() != "qgsWMSConnections" )
if ( root.tagName() != "qgs" + service.toUpper() + "Connections" )
{
QMessageBox::information( this, tr( "Loading connections" ),
tr( "The file is not an WMS connections exchange file." ) );
tr( "The file is not an %1 connections exchange file." ).arg( service ) );
return;
}

QString connectionName;
QSettings settings;
settings.beginGroup( "/Qgis/connections-wms" );
settings.beginGroup( "/Qgis/connections-" + service.toLower() );
QStringList keys = settings.childGroups();
settings.endGroup();
QDomElement child = root.firstChildElement();
Expand Down Expand Up @@ -489,7 +511,7 @@ void QgsManageConnectionsDialog::loadWMSConnections( const QDomDocument &doc, co
}

// no dups detected or overwrite is allowed
settings.beginGroup( "/Qgis/connections-wms" );
settings.beginGroup( "/Qgis/connections-" + service.toLower() );
settings.setValue( QString( "/" + connectionName + "/url" ) , child.attribute( "url" ) );
settings.setValue( QString( "/" + connectionName + "/ignoreGetMapURI" ), child.attribute( "ignoreGetMapURI" ) == "true" );
settings.setValue( QString( "/" + connectionName + "/ignoreGetFeatureInfoURI" ), child.attribute( "ignoreGetFeatureInfoURI" ) == "true" );
Expand All @@ -499,7 +521,7 @@ void QgsManageConnectionsDialog::loadWMSConnections( const QDomDocument &doc, co

if ( !child.attribute( "username" ).isEmpty() )
{
settings.beginGroup( "/Qgis/WMS/" + connectionName );
settings.beginGroup( "/Qgis/" + service.toUpper() + "/" + connectionName );
settings.setValue( "/username", child.attribute( "username" ) );
settings.setValue( "/password", child.attribute( "password" ) );
settings.endGroup();
Expand Down
5 changes: 3 additions & 2 deletions src/gui/qgsmanageconnectionsdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class GUI_EXPORT QgsManageConnectionsDialog : public QDialog, private Ui::QgsMan
PostGIS,
WFS,
MSSQL,
WCS
};

// constructor
Expand All @@ -53,11 +54,11 @@ class GUI_EXPORT QgsManageConnectionsDialog : public QDialog, private Ui::QgsMan

private:
bool populateConnections();
QDomDocument saveWMSConnections( const QStringList &connections );
QDomDocument saveOWSConnections( const QStringList &connections, const QString &service );
QDomDocument saveWFSConnections( const QStringList &connections );
QDomDocument savePgConnections( const QStringList & connections );
QDomDocument saveMssqlConnections( const QStringList & connections );
void loadWMSConnections( const QDomDocument &doc, const QStringList &items );
void loadOWSConnections( const QDomDocument &doc, const QStringList &items, const QString &service );
void loadWFSConnections( const QDomDocument &doc, const QStringList &items );
void loadPgConnections( const QDomDocument &doc, const QStringList &items );
void loadMssqlConnections( const QDomDocument &doc, const QStringList &items );
Expand Down
15 changes: 15 additions & 0 deletions src/gui/qgsnewhttpconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ QgsNewHttpConnection::QgsNewHttpConnection(
{
setupUi( this );

QString service = baseKey.mid( 18, 3 ).toUpper();
setWindowTitle( tr( "Create a new %1 connection" ).arg( service ) );

// It would be obviously much better to use mBaseKey also for credentials,
// but for some strange reason a different hardcoded key was used instead.
// WFS and WMS credentials were mixed with the same key WMS.
Expand Down Expand Up @@ -66,6 +69,18 @@ QgsNewHttpConnection::QgsNewHttpConnection(
txtUserName->setText( settings.value( credentialsKey + "/username" ).toString() );
txtPassword->setText( settings.value( credentialsKey + "/password" ).toString() );
}
if ( mBaseKey != "/Qgis/connections-wms/" )
{
cbxIgnoreGetMapURI->setVisible( false );
cbxIgnoreGetFeatureInfoURI->setVisible( false );
mGroupBox->layout()->removeWidget( cbxIgnoreGetMapURI );
mGroupBox->layout()->removeWidget( cbxIgnoreGetFeatureInfoURI );
// Adjust height
int w = width();
adjustSize();
resize( w, height() );

}

on_txtName_textChanged( connName );
}
Expand Down
798 changes: 798 additions & 0 deletions src/gui/qgsowssourceselect.cpp

Large diffs are not rendered by default.

237 changes: 237 additions & 0 deletions src/gui/qgsowssourceselect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/***************************************************************************
qgsowssourceselect.h - selector for WMS,WFS,WCS layers
-------------------
begin : 3 April 2005
original : (C) 2005 by Brendan Morley email : morb at ozemail dot com dot au
wms search : (C) 2009 Mathias Walker <mwa at sourcepole.ch>, Sourcepole AG
generalized : (C) 2012 Radim Blazek, based on qgsowsconnection.h
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSOWSSOURCESELECT_H
#define QGSOWSSOURCESELECT_H
#include "ui_qgsowssourceselectbase.h"
#include "qgsdatasourceuri.h"
#include "qgisgui.h"
#include "qgscontexthelp.h"

#include "qgsdataprovider.h"

#include <QStringList>
#include <QPushButton>

class QgisApp;
class QgsDataProvider;
class QButtonGroup;
class QgsNumericSortTreeWidgetItem;
class QDomDocument;
class QDomElement;

/** Formats supported by provider */
struct QgsOWSSupportedFormat
{
QString format;
QString label;
};

/*!
* \brief Dialog to create connections and add layers from WMS, WFS, WCS etc.
*
* This dialog allows the user to define and save connection information
* for WMS servers, etc.
*
* The user can then connect and add
* layers from the WMS server to the map canvas.
*/
class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase
{
Q_OBJECT

public:
//! Constructor
QgsOWSSourceSelect( QString service, QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags, bool managerMode = false, bool embeddedMode = false );
//! Destructor
~QgsOWSSourceSelect();

public slots:

//! Opens the create connection dialog to build a new connection
void on_mNewButton_clicked();
//! Opens a dialog to edit an existing connection
void on_mEditButton_clicked();
//! Deletes the selected connection
void on_mDeleteButton_clicked();
//! Saves connections to the file
void on_mSaveButton_clicked();
//! Loads connections from the file
void on_mLoadButton_clicked();

/*! Connects to the database using the stored connection parameters.
* Once connected, available layers are displayed.
*/
void on_mConnectButton_clicked();

//! Determines the layers the user selected
virtual void addClicked();

void searchFinished();

//! Opens the Spatial Reference System dialog.
void on_mChangeCRSButton_clicked();

//! Signaled when a layer selection is changed.
virtual void on_mLayersTreeWidget_itemSelectionChanged();

//! Set status message to theMessage
void showStatusMessage( QString const &theMessage );

//! show whatever error is exposed.
void showError( QString const &theTitle, QString const &theFormat, QString const &theError );

//! Stores the selected datasource whenerver it is changed
void on_mConnectionsComboBox_activated( int );

//! Add some default wms servers to the list
void on_mAddDefaultButton_clicked();

void on_mDialogButtonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }

signals:
void addRasterLayer( QString const & rasterLayerPath,
QString const & baseName,
QString const & providerKey );
void connectionsChanged();

protected:
/**
* List of image formats (encodings) supported by provider
* @return list of format/label pairs
*/
virtual QList<QgsOWSSupportedFormat> providerFormats();

//! List of formats supported for currently selected layer item(s)
virtual QStringList selectedLayersFormats();

//! Server CRS supported for currently selected layer item(s)
virtual QStringList selectedLayersCRSs();

//virtual QStringList layerCRS( int id );

//! Populate the connection list combo box
void populateConnectionList();

//! Populate supported formats
void populateFormats();

//! Clear previously set formats
void clearFormats();

//! Set supported CRSs
void populateCRS();

//! Connection name
QString connName();

//! Connection info (uri)
QString connectionInfo();

//! Set the server connection combo box to that stored in the config file.
void setConnectionListPosition();

//! Add a few example servers to the list.
void addDefaultServers();

//! Service name
QString mService;

//! Connections manager mode
bool mManagerMode;

//! Embedded mode, without 'Close'
bool mEmbeddedMode;


/**
* \brief Populate the layer list.
*
* \retval false if the layers could not be retrieved or parsed
*/
virtual void populateLayerList( );

//! create an item including possible parents
QgsNumericSortTreeWidgetItem *createItem( int id,
const QStringList &names,
QMap<int, QgsNumericSortTreeWidgetItem *> &items,
int &layerAndStyleCount,
const QMap<int, int> &layerParents,
const QMap<int, QStringList> &layerParentNames );

//! Returns a textual description for the authority id
QString descriptionForAuthId( QString authId );

//! layer name derived from latest layer selection (updated as long it's not edited manually)
QString mLastLayerName;

//! The widget that controls the image format radio buttons
QButtonGroup *mImageFormatGroup;

QPushButton *mAddButton;

QMap<QString, QString> mCrsNames;

void addWMSListRow( const QDomElement& item, int row );
void addWMSListItem( const QDomElement& el, int row, int column );

virtual void enableLayersForCrs( QTreeWidgetItem *item );

//! Returns currently selected format
QString selectedFormat();

//! Returns currently selected Crs
QString selectedCRS();

QList<QTreeWidgetItem*> mCurrentSelection;
QTableWidgetItem* mCurrentTileset;

//! Name for selected connection
QString mConnName;

//! Cnnection info for selected connection
QString mConnectionInfo;

//! URI for selected connection
QgsDataSourceURI mUri;

private:
//! Selected CRS
QString mSelectedCRS;

//! Common CRSs for selected layers
QSet<QString> mSelectedLayersCRSs;

//! Supported formats
QList<QgsOWSSupportedFormat> mProviderFormats;

//! Map mime type labels to supported formats
QMap<QString, QString> mMimeLabelMap;

private slots:
void on_mSearchButton_clicked();
void on_mAddWMSButton_clicked();
void on_mSearchTableWidget_itemSelectionChanged();
void on_mTilesetsTableWidget_itemClicked( QTableWidgetItem *item );
void on_mLayerUpButton_clicked();
void on_mLayerDownButton_clicked();
virtual void updateButtons();
};

#endif // QGSOWSSOURCESELECT_H
1 change: 1 addition & 0 deletions src/providers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ADD_SUBDIRECTORY(osm)
ADD_SUBDIRECTORY(sqlanywhere)
ADD_SUBDIRECTORY(gdal)
ADD_SUBDIRECTORY(mssql)
ADD_SUBDIRECTORY(ows)

IF (POSTGRES_FOUND)
ADD_SUBDIRECTORY(postgres)
Expand Down
17 changes: 15 additions & 2 deletions src/providers/gdal/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
SET(GDAL_SRCS qgsgdalprovider.cpp qgsgdaldataitems.cpp)
SET(GDAL_MOC_HDRS qgsgdalprovider.h)
SET(GDAL_SRCS
qgsgdalprovider.cpp
qgsgdaldataitems.cpp
qgswcscapabilities.cpp
qgswcssourceselect.cpp
)
SET(GDAL_MOC_HDRS
qgsgdalprovider.h
qgsgdaldataitems.h
qgswcscapabilities.h
qgswcssourceselect.h
)

INCLUDE_DIRECTORIES (
../../core
../../core/raster
../../gui
${CMAKE_CURRENT_BINARY_DIR}/../../ui
${GDAL_INCLUDE_DIR}
# ${PROJ_INCLUDE_DIR}
# ${GEOS_INCLUDE_DIR}
Expand All @@ -14,6 +26,7 @@ ADD_LIBRARY (gdalprovider MODULE ${GDAL_SRCS} ${GDAL_MOC_SRCS})

TARGET_LINK_LIBRARIES (gdalprovider
qgis_core
qgis_gui
)

INSTALL(TARGETS gdalprovider
Expand Down
277 changes: 275 additions & 2 deletions src/providers/gdal/qgsgdaldataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include "qgsgdaldataitems.h"
#include "qgsgdalprovider.h"
#include "qgslogger.h"
#include "qgsdatasourceuri.h"
#include "qgswcssourceselect.h"
#include "qgsowsconnection.h"
#include "qgsnewhttpconnection.h"

#include <QFileInfo>
#include <QSettings>
Expand Down Expand Up @@ -112,6 +116,259 @@ QString QgsGdalLayerItem::layerName() const
return info.completeBaseName();
}

// ---------------------------------------------------------------------------
QgsWCSConnectionItem::QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mIcon = QIcon( getThemePixmap( "mIconWcs.png" ) );
}

QgsWCSConnectionItem::~QgsWCSConnectionItem()
{
QgsDebugMsg( "Entered" );
}

QVector<QgsDataItem*> QgsWCSConnectionItem::createChildren()
{
QgsDebugMsg( "Entered" );
QVector<QgsDataItem*> children;

QString encodedUri = mPath;
QgsDataSourceURI uri;
uri.setEncodedUri( encodedUri );
QgsDebugMsg( "encodedUri = " + encodedUri );

mCapabilities.setUri( uri );

// Attention: supportedLayers() gives tree leafes, not top level
if ( !mCapabilities.lastError().isEmpty() )
{
//children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) );
// TODO: show the error without adding child
return children;
}

foreach( QgsWcsCoverageSummary coverageSummary, mCapabilities.capabilities().contents.coverageSummary )
{
// Attention, the name may be empty
QgsDebugMsg( QString::number( coverageSummary.orderId ) + " " + coverageSummary.identifier + " " + coverageSummary.title );
QString pathName = coverageSummary.identifier.isEmpty() ? QString::number( coverageSummary.orderId ) : coverageSummary.identifier;

QgsWCSLayerItem * layer = new QgsWCSLayerItem( this, coverageSummary.title, mPath + "/" + pathName, mCapabilities.capabilities(), uri, coverageSummary );

children.append( layer );
}
return children;
}

bool QgsWCSConnectionItem::equal( const QgsDataItem *other )
{
if ( type() != other->type() )
{
return false;
}
const QgsWCSConnectionItem *o = dynamic_cast<const QgsWCSConnectionItem *>( other );
if ( !o )
{
return false;
}

return ( mPath == o->mPath && mName == o->mName );
}

QList<QAction*> QgsWCSConnectionItem::actions()
{
QList<QAction*> lst;

QAction* actionEdit = new QAction( tr( "Edit..." ), this );
connect( actionEdit, SIGNAL( triggered() ), this, SLOT( editConnection() ) );
lst.append( actionEdit );

QAction* actionDelete = new QAction( tr( "Delete" ), this );
connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteConnection() ) );
lst.append( actionDelete );

return lst;
}

void QgsWCSConnectionItem::editConnection()
{
QgsNewHttpConnection nc( 0, "/Qgis/connections-wcs/", mName );

if ( nc.exec() )
{
// the parent should be updated
mParent->refresh();
}
}

void QgsWCSConnectionItem::deleteConnection()
{
QgsOWSConnection::deleteConnection( "WCS", mName );
// the parent should be updated
mParent->refresh();
}


// ---------------------------------------------------------------------------

QgsWCSLayerItem::QgsWCSLayerItem( QgsDataItem* parent, QString name, QString path, QgsWcsCapabilitiesProperty capabilitiesProperty, QgsDataSourceURI dataSourceUri, QgsWcsCoverageSummary coverageSummary )
: QgsLayerItem( parent, name, path, QString(), QgsLayerItem::Raster, "gdal" ),
mCapabilities( capabilitiesProperty ),
mDataSourceUri( dataSourceUri ),
mCoverageSummary( coverageSummary )
{
QgsDebugMsg( "uri = " + mDataSourceUri.encodedUri() );
mUri = createUri();
// Populate everything, it costs nothing, all info about layers is collected
foreach( QgsWcsCoverageSummary coverageSummary, mCoverageSummary.coverageSummary )
{
// Attention, the name may be empty
QgsDebugMsg( QString::number( coverageSummary.orderId ) + " " + coverageSummary.identifier + " " + coverageSummary.title );
QString pathName = coverageSummary.identifier.isEmpty() ? QString::number( coverageSummary.orderId ) : coverageSummary.identifier;
QgsWCSLayerItem * layer = new QgsWCSLayerItem( this, coverageSummary.title, mPath + "/" + pathName, mCapabilities, mDataSourceUri, coverageSummary );
mChildren.append( layer );
}

if ( mChildren.size() == 0 )
{
//mIcon = iconRaster();
mIcon = QIcon( getThemePixmap( "mIconWcs.png" ) );
}
mPopulated = true;
}

QgsWCSLayerItem::~QgsWCSLayerItem()
{
}

QString QgsWCSLayerItem::createUri()
{
if ( mCoverageSummary.identifier.isEmpty() )
return ""; // layer collection

// Number of styles must match number of layers
mDataSourceUri.setParam( "identifier", mCoverageSummary.identifier );

// TODO(?): with WCS 1.0 GetCapabilities does not contain CRS and formats,
// to get them we would need to call QgsWcsCapabilities::describeCoverage
// but it is problematic to get QgsWcsCapabilities here (copy not allowed
// by QObject, pointer is dangerous (OWS provider is changing parent))
// We leave CRS and format default for now.

QString format;
// get first supported by GDAL and server
QStringList mimes = QgsGdalProvider::supportedMimes().keys();
// prefer tiff
if ( mimes.contains( "image/tiff" ) && mCoverageSummary.supportedFormat.contains( "image/tiff" ) )
{
format = "image/tiff";
}
else
{
foreach( QString f, mimes )
{
if ( mCoverageSummary.supportedFormat.indexOf( f ) >= 0 )
{
format = f;
break;
}
}
}
if ( !format.isEmpty() )
{
mDataSourceUri.setParam( "format", format );
}

QString crs;

// TODO: prefer project CRS
// get first known if possible
QgsCoordinateReferenceSystem testCrs;
foreach( QString c, mCoverageSummary.supportedCrs )
{
testCrs.createFromOgcWmsCrs( c );
if ( testCrs.isValid() )
{
crs = c;
break;
}
}
if ( crs.isEmpty() && mCoverageSummary.supportedCrs.size() > 0 )
{
crs = mCoverageSummary.supportedCrs.value( 0 );
}
if ( !crs.isEmpty() )
{
mDataSourceUri.setParam( "crs", crs );
}

return mDataSourceUri.encodedUri();
}

// ---------------------------------------------------------------------------

QgsWCSRootItem::QgsWCSRootItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mIcon = QIcon( getThemePixmap( "mIconWcs.png" ) );

populate();
}

QgsWCSRootItem::~QgsWCSRootItem()
{
}

QVector<QgsDataItem*>QgsWCSRootItem::createChildren()
{
QVector<QgsDataItem*> connections;
foreach( QString connName, QgsOWSConnection::connectionList( "WCS" ) )
{
//QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, mPath + "/" + connName );
QgsOWSConnection connection( "WCS", connName );
QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, connection.uri().encodedUri() );

conn->setIcon( QIcon( getThemePixmap( "mIconConnect.png" ) ) );
connections.append( conn );
}
return connections;
}

QList<QAction*> QgsWCSRootItem::actions()
{
QList<QAction*> lst;

QAction* actionNew = new QAction( tr( "New Connection..." ), this );
connect( actionNew, SIGNAL( triggered() ), this, SLOT( newConnection() ) );
lst.append( actionNew );

return lst;
}


QWidget * QgsWCSRootItem::paramWidget()
{
QgsWCSSourceSelect *select = new QgsWCSSourceSelect( 0, 0, true, true );
connect( select, SIGNAL( connectionsChanged() ), this, SLOT( connectionsChanged() ) );
return select;
return 0;
}
void QgsWCSRootItem::connectionsChanged()
{
refresh();
}

void QgsWCSRootItem::newConnection()
{
QgsNewHttpConnection nc( 0, "/Qgis/connections-wcs/" );

if ( nc.exec() )
{
refresh();
}
}

// ---------------------------------------------------------------------------

static QString filterString;
Expand All @@ -120,13 +377,24 @@ static QStringList wildcards = QStringList();

QGISEXTERN int dataCapabilities()
{
return QgsDataProvider::File | QgsDataProvider::Dir;
return QgsDataProvider::File | QgsDataProvider::Dir | QgsDataProvider::Net;
}

QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
{
QgsDebugMsg( "thePath = " + thePath );
if ( thePath.isEmpty() )
return 0;
{
// Top level WCS
return new QgsWCSRootItem( parentItem, "WCS", "wcs:" );
}

if ( thePath.contains( "url=" ) )
{
// OWS server
QgsDebugMsg( "connection found in uri" );
return new QgsWCSConnectionItem( parentItem, "WCS", thePath );
}

// zip settings + info
QSettings settings;
Expand Down Expand Up @@ -259,3 +527,8 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )

return item;
}

QGISEXTERN QgsWCSSourceSelect * selectWidget( QWidget * parent, Qt::WFlags fl )
{
return new QgsWCSSourceSelect( parent, fl );
}
58 changes: 58 additions & 0 deletions src/providers/gdal/qgsgdaldataitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#define QGSGDALDATAITEMS_H

#include "qgsdataitem.h"
#include "qgsdatasourceuri.h"
//#include "qgsowsconnection.h"
#include "qgswcscapabilities.h"

class QgsGdalLayerItem : public QgsLayerItem
{
Expand All @@ -37,5 +40,60 @@ class QgsGdalLayerItem : public QgsLayerItem
QString layerName() const;
};

class QgsWCSConnectionItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path );
~QgsWCSConnectionItem();

QVector<QgsDataItem*> createChildren();
virtual bool equal( const QgsDataItem *other );

virtual QList<QAction*> actions();

QgsWcsCapabilities mCapabilities;
QVector<QgsWcsCoverageSummary> mLayerProperties;

public slots:
void editConnection();
void deleteConnection();
};

// WCS Layers may be nested, so that they may be both QgsDataCollectionItem and QgsLayerItem
// We have to use QgsDataCollectionItem and support layer methods if necessary
class QgsWCSLayerItem : public QgsLayerItem
{
Q_OBJECT
public:
QgsWCSLayerItem( QgsDataItem* parent, QString name, QString path,
QgsWcsCapabilitiesProperty capabilitiesProperty, QgsDataSourceURI dataSourceUri, QgsWcsCoverageSummary coverageSummary );
~QgsWCSLayerItem();

QString createUri();

QgsWcsCapabilitiesProperty mCapabilities;
QgsDataSourceURI mDataSourceUri;
QgsWcsCoverageSummary mCoverageSummary;
};

class QgsWCSRootItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsWCSRootItem( QgsDataItem* parent, QString name, QString path );
~QgsWCSRootItem();

QVector<QgsDataItem*> createChildren();

virtual QList<QAction*> actions();

virtual QWidget * paramWidget();

public slots:
void connectionsChanged();

void newConnection();
};

#endif // QGSGDALDATAITEMS_H
109 changes: 106 additions & 3 deletions src/providers/gdal/qgsgdalprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
#include "qgsapplication.h"
#include "qgscoordinatetransform.h"
#include "qgsdataitem.h"
#include "qgsdatasourceuri.h"
#include "qgsmessagelog.h"
#include "qgsrectangle.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsrasterbandstats.h"
#include "qgsrasterlayer.h"
#include "qgsrasterpyramid.h"
#include "qgswcscapabilities.h"

#include <QImage>
#include <QSettings>
Expand All @@ -41,6 +44,7 @@
#include <QHash>
#include <QTime>
#include <QSettings>
#include <QTextDocument>

#include "gdalwarper.h"
#include "ogr_spatialref.h"
Expand Down Expand Up @@ -122,13 +126,79 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri )
QgsDebugMsg( QString( "Trying /vsigzip syntax, uri= %1" ).arg( dataSourceUri() ) );
}

//mGdalBaseDataset = GDALOpen( QFile::encodeName( uri ).constData(), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly );
// The uri is either a file name or encoded parameters for WCS
QString gdalUri = dataSourceUri();
if ( uri.contains( "url=" ) && uri.contains( "identifier=" ) && !QFile::exists( uri ) )
{
// - GDAL currently (4/2012) supports WCS 1.0.0 (default) and 1.1.0
// We cannot use 1.1.0 because of wrong longlat bbox send by GDAL
// and impossibility to set GridOffsets.

// - WCS 1.0.0 does not work with GDAL r24316 2012-04-25 + Mapserver 6.0.2
// 1) with geographic CRS
// GDAL sends BOUNDINGBOX=min_long,min_lat,max_lon,max_lat,urn:ogc:def:crs:EPSG::4326
// Mapserver works with min_lat,min_long,max_lon,max_lat
// OGC 07-067r5 (WCS 1.1.2) referes to OGC 06-121r3 which says:
// "The number of axes included, and the order of these axes, shall be as
// specified by the referenced CRS."
// EPSG defines for EPSG:4326 Axes: latitude, longitude
// (don't confuse with OGC:CRS84 with lon,lat order)
// Created a ticket: http://trac.osgeo.org/gdal/ticket/4639

// 2) Mapserver ignores RangeSubset (not implemented in mapserver)
// and GDAL fails with "Returned tile does not match expected band count"
// because it requested single band but recieved all bands
// Created ticket: https://github.com/mapserver/mapserver/issues/4299

// Other problems:
// - GDAL WCS fails to open 1.1 with space in RangeSubset, there is a ticket about
// it http://trac.osgeo.org/gdal/ticket/1833 without conclusion, Frank suggests
// that ServiceURL should be expected to be escaped while CoverageName should not

QgsDataSourceURI dsUri;
dsUri.setEncodedUri( uri );
gdalUri = "<WCS_GDAL>";
gdalUri += "<Version>1.0.0</Version>";
//gdalUri += "<Version>1.1.0</Version>";
// prepareUri adds ? or & if necessary, GDAL fails otherwise
gdalUri += "<ServiceURL>" + Qt::escape( QgsWcsCapabilities::prepareUri( dsUri.param( "url" ) ) ) + "</ServiceURL>";
gdalUri += "<CoverageName>" + dsUri.param( "identifier" ) + "</CoverageName>";

if ( dsUri.hasParam( "format" ) )
{
gdalUri += "<PreferredFormat>" + dsUri.param( "format" ) + "</PreferredFormat>";
}

// - CRS : there is undocumented GDAL CRS tag, but it only overrides CRS param
// in requests but the BBOX is left unchanged and thus results in server error (usually).
// 1.0 : RESPONSE_CRS
if ( dsUri.hasParam( "crs" ) )
{
gdalUri += "<GetCoverageExtra>&amp;RESPONSE_CRS=" + dsUri.param( "crs" ) + "</GetCoverageExtra>";
}
// 1.1 : Required parameters are: GridBaseCRS and GridOffsets (resolution)
// We dont have the GridOffsets here and it should be probably dynamic
// according to requested data (zoom).
// Mapserver 6.0.2 works without the GridOffsets, but other servers may not.
//QString crsUrn = "urn:ogc:def:crs:" + dsUri.param("crs").replace(":","::");
//gdalUri += "<GetCoverageExtra>&amp;GridBaseCRS=" + crsUrn + "</GetCoverageExtra>";

if ( dsUri.hasParam( "username" ) && dsUri.hasParam( "password" ) )
{
gdalUri += "<UserPwd>" + dsUri.param( "username" ) + ":" + dsUri.param( "password" ) + "</UserPwd>";
}
gdalUri += "</WCS_GDAL>";
QgsDebugMsg( "WCS uri: " + gdalUri );
}

CPLErrorReset();
mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), GA_ReadOnly );

if ( !mGdalBaseDataset )
{
QgsDebugMsg( QString( "Cannot open GDAL dataset %1: %2" ).arg( dataSourceUri() ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
QString msg = QString( "Cannot open GDAL dataset %1:\n%2" ).arg( dataSourceUri() ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) );
QgsDebugMsg( msg );
QgsMessageLog::logMessage( msg );
return;
}

Expand Down Expand Up @@ -1188,6 +1258,8 @@ int QgsGdalProvider::srcDataType( int bandNo ) const

int QgsGdalProvider::dataType( int bandNo ) const
{
if ( mGdalDataType.size() == 0 ) return QgsRasterDataProvider::UnknownDataType;

return dataTypeFormGdal( mGdalDataType[bandNo-1] );
}

Expand Down Expand Up @@ -2002,3 +2074,34 @@ QGISEXTERN void buildSupportedRasterFileFilter( QString & theFileFiltersString )
buildSupportedRasterFileFilterAndExtensions( theFileFiltersString, exts, wildcards );
}

QMap<QString, QString> QgsGdalProvider::supportedMimes()
{
QMap<QString, QString> mimes;
GDALAllRegister();

QgsDebugMsg( QString( "GDAL drivers cont %1" ).arg( GDALGetDriverCount() ) );
for ( int i = 0; i < GDALGetDriverCount(); ++i )
{
GDALDriverH driver = GDALGetDriver( i );
Q_CHECK_PTR( driver );

if ( !driver )
{
QgsLogger::warning( "unable to get driver " + QString::number( i ) );
continue;
}

QString desc = GDALGetDescription( driver );

QString mimeType = GDALGetMetadataItem( driver, "DMD_MIMETYPE", "" );

if ( mimeType.isEmpty() ) continue;

desc = desc.isEmpty() ? mimeType : desc;

QgsDebugMsg( "add GDAL format " + mimeType + " " + desc );

mimes[mimeType] = desc;
}
return mimes;
}
2 changes: 2 additions & 0 deletions src/providers/gdal/qgsgdalprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ class QgsGdalProvider : public QgsRasterDataProvider
/** Emit a signal to notify of the progress event. */
void emitProgress( int theType, double theProgress, QString theMessage );

static QMap<QString, QString> supportedMimes();

signals:
void statusChanged( QString );

Expand Down
873 changes: 873 additions & 0 deletions src/providers/gdal/qgswcscapabilities.cpp

Large diffs are not rendered by default.

362 changes: 362 additions & 0 deletions src/providers/gdal/qgswcscapabilities.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,362 @@
/***************************************************************************
qgswcscapabilities.h - WCS capabilities
-------------------
begin : 17 Mar, 2005
copyright : (C) 2005 by Brendan Morley
email : morb at ozemail dot com dot au
wcs : 4/2012 Radim Blazek, based on qgswmsprovider.h
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSWCSCAPABILITIES_H
#define QGSWCSCAPABILITIES_H

//#include "qgsrasterdataprovider.h"
#include "qgsdatasourceuri.h"
#include "qgsrectangle.h"

#include <QString>
#include <QStringList>
#include <QDomElement>
#include <QMap>
#include <QVector>
#include <QUrl>

class QgsCoordinateTransform;
class QNetworkAccessManager;
class QNetworkReply;
class QNetworkRequest;

/*
* The following structs reflect the WCS XML schema,
* as illustrated in ... the Web Coverage Service standard, version x.x xxxx-xx-xx.
*/

/** Get Property structure */
struct QgsWcsGet
{
QString xlinkHref;
};

/** HTTP Property structure */
struct QgsWcsHTTP
{
QgsWcsGet get;
};

/** DCP Type Property structure */
struct QgsWcsDCP
{
QgsWcsHTTP http;
};

/** Version parameter */
struct QgsWcsVersion
{
QStringList allowedValues;
};

/** Operation type structure */
struct QgsWcsOperation
{
QgsWcsVersion version;
QgsWcsDCP dcp;
};

/** OperationsMetadata */
struct QgsWcsOperationsMetadata
{
QgsWcsOperation getCoverage;
};

/** ServiceerviceIdentification structure */
struct QgsWcsServiceIdentification
{
QString title;
QString abstract;
};

/** CoverageSummary structure */
struct QgsWcsCoverageSummary
{
int orderId;
QString identifier;
QString title;
QString abstract;
QStringList supportedCrs;
QStringList supportedFormat;
QgsRectangle wgs84BoundingBox;
QVector<QgsWcsCoverageSummary> coverageSummary;
bool described; // 1.0
};

/** Contents structure */
/*
struct QgsWcsContents
{
QStringList supportedCrs;
QStringList supportedFormat;
QVector<QgsWcsCoverageSummary> coverageSummary;
};
*/

/** Capability Property structure */
struct QgsWcsCapabilitiesProperty
{
QString version;
QgsWcsServiceIdentification serviceIdentification;
QgsWcsOperationsMetadata operationsMetadata;
// QgsWcsContents contents;
// using QgsWcsCoverageSummary for contents for simplification
QgsWcsCoverageSummary contents;
};

/**
\brief Data provider for OGC WCS layers.
*/
class QgsWcsCapabilities : public QObject
{
Q_OBJECT

public:
/**
* Constructor for the provider.
*
* \param uri HTTP URL of the Web Server. If needed a proxy will be used
* otherwise we contact the host directly.
*
*/
QgsWcsCapabilities( QgsDataSourceURI const & theUri );
QgsWcsCapabilities( );

//! Destructor
~QgsWcsCapabilities();

void setUri( QgsDataSourceURI const &theUri );

QgsWcsCapabilitiesProperty capabilities();

/**
* \brief Returns a list of the supported layers of the WCS server
*
* \param[out] layers The list of layers will be placed here.
*
* \retval false if the layers could not be retrieved or parsed -
* see lastError() for more info
*/
bool supportedCoverages( QVector<QgsWcsCoverageSummary> &coverageSummary );


/**
* \brief Returns a map for the hierarchy of layers
*/
void coverageParents( QMap<int, int> &parents, QMap<int, QStringList> &parentNames ) const;

//! Get coverage summare for identifier
QgsWcsCoverageSummary * coverageSummary( QString const & theIdentifier, QgsWcsCoverageSummary* parent = 0 );

/**
* \brief Prepare the URI so that we can later simply append param=value
* \param uri uri to prepare
* \retval prepared uri
*/
static QString prepareUri( QString uri );

/**Returns the GetCoverage url
* @added in 1.5
*/
QString getCoverageUrl() const;

//! Send request to server
bool sendRequest( QString const & url );

/** Get additional coverage info from server. Version 1.0 GetCapabilities
* response does not contain all info (CRS, formats).
*/
bool describeCoverage( QString const &identifier, bool forceRefresh = false );

bool convertToDom( QByteArray const &xml );
bool parseDescribeCoverageDom( QByteArray const &xml, QgsWcsCoverageSummary *coverage );

//! set authorization header
void setAuthorization( QNetworkRequest &request ) const;

/**
* \brief Returns the caption error text for the last error in this provider
*
* If an operation returns 0 (e.g. draw()), this function
* returns the text of the error associated with the failure.
* Interactive users of this provider can then, for example,
* call a QMessageBox to display the contents.
*/
QString lastErrorTitle();

/**
* \brief Returns the verbose error text for the last error in this provider
*
* If an operation returns 0 (e.g. draw()), this function
* returns the text of the error associated with the failure.
* Interactive users of this provider can then, for example,
* call a QMessageBox to display the contents.
*/
QString lastError();

/**
* \brief Returns the format of the error message (text or html)
*/
QString lastErrorFormat();

signals:

/** \brief emit a signal to notify of a progress event */
void progressChanged( int theProgress, int theTotalSteps );

/** \brief emit a signal to be caught by qgisapp and display a msg on status bar */
void statusChanged( QString const & theStatusQString );

private slots:
void capabilitiesReplyFinished();
void capabilitiesReplyProgress( qint64, qint64 );

private:
void showMessageBox( const QString &title, const QString &text );

//! Get tag name without namespace
QString stripNS( const QString &name );

//! Get text of first child of specified name, NS is ignored
QString firstChildText( const QDomElement &element, const QString &name );

//! Get first child of specified name, NS is ignored
QDomElement firstChild( const QDomElement &element, const QString &name );

/**
* \brief Retrieve and parse the (cached) Capabilities document from the server
*
* \param forceRefresh if true, ignores any previous response cached in memory
* and always contact the server for a new copy.
* \retval false if the capabilities document could not be retrieved or parsed -
* see lastError() for more info
*
* When this returns, "layers" will make sense.
*
* TODO: Make network-timeout tolerant
*/
bool retrieveServerCapabilities( bool forceRefresh = false );

//! \return false if the capabilities document could not be parsed - see lastError() for more info
bool parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapabilitiesProperty &capabilities );

// ------------- 1.0 --------------------
//! parse the WCS Service XML element
void parseService( QDomElement const &e, QgsWcsServiceIdentification &serviceIdentification );

//! parse the WCS Capability XML element
void parseCapability( QDomElement const &e, QgsWcsOperationsMetadata &operationsMetadata );

//! parse the WCS Layer XML element
void parseContentMetadata( QDomElement const &e, QgsWcsCoverageSummary &coverageSummary );

//! parse the WCS Layer XML element
void parseCoverageOfferingBrief( QDomElement const &e, QgsWcsCoverageSummary &coverageSummary,
QgsWcsCoverageSummary *parent = 0 );

// ------------- 1.1 --------------------
//! parse the WCS ServiceIdentificatio XML element
void parseServiceIdentification( QDomElement const &e, QgsWcsServiceIdentification &serviceIdentification );

//! parse the WCS OperationsMetadata XML element
void parseOperationsMetadata( QDomElement const &e, QgsWcsOperationsMetadata &operationsMetadata );

//! parse the WCS GetCoverage
void parseOperation( QDomElement const & e, QgsWcsOperation& operation );

//! parse the WCS HTTP XML element
void parseHttp( QDomElement const &e, QgsWcsHTTP &http );

//! parse the WCS DCPType XML element
void parseDcp( QDomElement const &e, QgsWcsDCP &dcp );

//! parse the WCS Layer XML element
void parseCoverageSummary( QDomElement const &e, QgsWcsCoverageSummary &coverageSummary,
QgsWcsCoverageSummary *parent = 0 );

//! Data source uri
QgsDataSourceURI mUri;

//! Response capabilities version
QString mVersion;

/**
* Capabilities of the WCS Server (raw)
*/
QByteArray mCapabilitiesResponse;

/**
* Capabilities of the WCS Server
*/
QDomDocument mCapabilitiesDom;

/**
* Last Service Exception Report from the WCS Server
*/
QDomDocument mServiceExceptionReportDom;

/**
* Parsed capabilities of the WCS Server
*/
QgsWcsCapabilitiesProperty mCapabilities;

/**
* layers hosted by the WCS Server
* This vector contain initial copies which are not updated by coverageSummary()!!!
*/
QVector<QgsWcsCoverageSummary> mCoveragesSupported;

/**
* The reply to the capabilities request
*/
QNetworkReply *mCapabilitiesReply;

/**
* The error caption associated with the last WCS error.
*/
QString mErrorTitle;

/**
* The error message associated with the last WCS error.
*/
QString mError;

/** The mime type of the message
*/
QString mErrorFormat;

int mCoverageCount;

//! number of layers and parents
QMap<int, int> mCoverageParents;
QMap<int, QStringList> mCoverageParentIdentifiers;

//! Username for basic http authentication
QString mUserName;

//! Password for basic http authentication
QString mPassword;
};


#endif

// ENDS
239 changes: 239 additions & 0 deletions src/providers/gdal/qgswcssourceselect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
/***************************************************************************
qgswcssourceselect.cpp - selector for WCS
-------------------
begin : 04 2012
copyright :
original : (C) 2012 Radim Blazek
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgis.h"
#include "qgslogger.h"

#include "qgsgdalprovider.h"
#include "qgswcssourceselect.h"
#include "qgswcscapabilities.h"
#include "qgsnumericsortlistviewitem.h"

#include <QWidget>

#define CPL_SUPRESS_CPLUSPLUS
#include <gdal.h>

#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
#define TO8F(x) (x).toUtf8().constData()
#define FROM8(x) QString::fromUtf8(x)
#else
#define TO8F(x) QFile::encodeName( x ).constData()
#define FROM8(x) QString::fromLocal8Bit(x)
#endif

QgsWCSSourceSelect::QgsWCSSourceSelect( QWidget * parent, Qt::WFlags fl, bool managerMode, bool embeddedMode )
: QgsOWSSourceSelect( "WCS", parent, fl, managerMode, embeddedMode )
{
// Hide irrelevant widgets
mWMSGroupBox->hide();
mLayersTab->layout()->removeWidget( mWMSGroupBox );
mTabWidget->removeTab( mTabWidget->indexOf( mLayerOrderTab ) );
mTabWidget->removeTab( mTabWidget->indexOf( mTilesetsTab ) );
mTabWidget->removeTab( mTabWidget->indexOf( mSearchTab ) );
mAddDefaultButton->hide();

mLayersTreeWidget->setSelectionMode( QAbstractItemView::SingleSelection );
}

QgsWCSSourceSelect::~QgsWCSSourceSelect()
{
}

void QgsWCSSourceSelect::populateLayerList( )
{
QgsDebugMsg( "entered" );

mLayersTreeWidget->clear();

mCapabilities.setUri( mUri );

if ( !mCapabilities.lastError().isEmpty() )
{
showError( mCapabilities.lastErrorTitle(), mCapabilities.lastErrorFormat(), mCapabilities.lastError() );
return;
}

QVector<QgsWcsCoverageSummary> coverages;
if ( !mCapabilities.supportedCoverages( coverages ) )
return;

QMap<int, QgsNumericSortTreeWidgetItem *> items;
QMap<int, int> coverageParents;
QMap<int, QStringList> coverageParentNames;
mCapabilities.coverageParents( coverageParents, coverageParentNames );

mLayersTreeWidget->setSortingEnabled( true );

int coverageAndStyleCount = -1;

for ( QVector<QgsWcsCoverageSummary>::iterator coverage = coverages.begin();
coverage != coverages.end();
coverage++ )
{
QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2" ).arg( coverage->orderId ).arg( coverage->identifier ) );

QgsNumericSortTreeWidgetItem *lItem = createItem( coverage->orderId, QStringList() << coverage->identifier << coverage->title << coverage->abstract, items, coverageAndStyleCount, coverageParents, coverageParentNames );

lItem->setData( 0, Qt::UserRole + 0, coverage->identifier );
lItem->setData( 0, Qt::UserRole + 1, "" );

// Make only leaves selectable
if ( coverageParents.keys( coverage->orderId ).size() > 0 )
{
lItem->setFlags( Qt::ItemIsEnabled );
}
}

mLayersTreeWidget->sortByColumn( 0, Qt::AscendingOrder );

// If we got some coverages, let the user add them to the map
if ( mLayersTreeWidget->topLevelItemCount() == 1 )
{
mLayersTreeWidget->expandItem( mLayersTreeWidget->topLevelItem( 0 ) );
}
}

QString QgsWCSSourceSelect::selectedIdentifier()
{
QList<QTreeWidgetItem *> selectionList = mLayersTreeWidget->selectedItems();
if ( selectionList.size() < 1 ) return QString(); // should not happen
QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString();
QgsDebugMsg( " identifier = " + identifier );
return identifier;
}

void QgsWCSSourceSelect::addClicked( )
{
QgsDebugMsg( "entered" );
QgsDataSourceURI uri = mUri;

QString identifier = selectedIdentifier();
if ( identifier.isEmpty() ) { return; }

uri.setParam( "identifier", identifier );

// Set crs only if necessary (multiple offered), so that we can decide in the
// provider if WCS 1.0 with RESPONSE_CRS has to be used. Not perfect, they can
// add more CRS in future and URI will be saved in project without any.
if ( selectedLayersCRSs().size() > 1 )
{
uri.setParam( "crs", selectedCRS() );
}

QgsDebugMsg( "selectedFormat = " + selectedFormat() );
if ( !selectedFormat().isEmpty() )
{
uri.setParam( "format", selectedFormat() );
}

emit addRasterLayer( uri.encodedUri(), identifier, "gdal" );
}

void QgsWCSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged()
{
QgsDebugMsg( "entered" );

QString identifier = selectedIdentifier();
if ( identifier.isEmpty() ) { return; }

mCapabilities.describeCoverage( identifier ); // 1.0 get additional info

populateFormats();

populateCRS();

updateButtons();

mAddButton->setEnabled( true );
}

void QgsWCSSourceSelect::updateButtons()
{
QgsDebugMsg( "entered" );

if ( mLayersTreeWidget->selectedItems().isEmpty() )
{
showStatusMessage( tr( "Select a layer" ) );
}
else
{
if ( selectedCRS().isEmpty() )
{
showStatusMessage( tr( "No CRS selected" ) );
}
}

mAddButton->setEnabled( !mLayersTreeWidget->selectedItems().isEmpty() && !selectedCRS().isEmpty() && !selectedFormat().isEmpty() );
}

QList<QgsOWSSupportedFormat> QgsWCSSourceSelect::providerFormats()
{
QgsDebugMsg( "entered" );
QList<QgsOWSSupportedFormat> formats;

QMap<QString, QString> mimes = QgsGdalProvider::supportedMimes();
foreach( QString mime, mimes.keys() )
{
QgsOWSSupportedFormat format = { mime, mimes.value( mime ) };

// prefer tiff
if ( mime == "image/tiff" )
{
formats.prepend( format );
}
else
{
formats.append( format );
}
}

return formats;
}

QStringList QgsWCSSourceSelect::selectedLayersFormats()
{
QgsDebugMsg( "entered" );

QString identifier = selectedIdentifier();
if ( identifier.isEmpty() ) { return QStringList(); }

QgsWcsCoverageSummary * c = mCapabilities.coverageSummary( identifier );
if ( !c ) { return QStringList(); }

QgsDebugMsg( "supportedFormat = " + c->supportedFormat.join( "," ) );
return c->supportedFormat;
}

QStringList QgsWCSSourceSelect::selectedLayersCRSs()
{
QgsDebugMsg( "entered" );

QString identifier = selectedIdentifier();
if ( identifier.isEmpty() ) { return QStringList(); }

QgsWcsCoverageSummary * c = mCapabilities.coverageSummary( identifier );
if ( !c ) { return QStringList(); }

return c->supportedCrs;
}

void QgsWCSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item )
{
// TODO: I am not convinced to disable layers according to selected CRS
}
83 changes: 83 additions & 0 deletions src/providers/gdal/qgswcssourceselect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/***************************************************************************
qgswcssourceselect.h - selector for WCS layers
-------------------
begin : 3 April 2005
original : (C) 2005 by Brendan Morley email : morb at ozemail dot com dot au
wms search : (C) 2009 Mathias Walker <mwa at sourcepole.ch>, Sourcepole AG
generalized : (C) 2012 Radim Blazek, based on qgsowsconnection.h
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSWCSSOURCESELECT_H
#define QGSWCSSOURCESELECT_H
#include "qgsowssourceselect.h"
#include "qgsdatasourceuri.h"
#include "qgisgui.h"
#include "qgscontexthelp.h"
#include "qgswcscapabilities.h"

#include "qgsdataprovider.h"

#include <QStringList>
#include <QPushButton>

class QgisApp;
class QgsDataProvider;
class QButtonGroup;
class QgsNumericSortTreeWidgetItem;
class QDomDocument;
class QDomElement;

/*!
* \brief Dialog to create connections and add layers from WMS, WFS, WCS etc.
*
* This dialog allows the user to define and save connection information
* for WMS servers, etc.
*
* The user can then connect and add
* layers from the WMS server to the map canvas.
*/
class QgsWCSSourceSelect : public QgsOWSSourceSelect
{
Q_OBJECT

public:
//! Constructor
QgsWCSSourceSelect( QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags, bool managerMode = false, bool embeddedMode = false );
//! Destructor
~QgsWCSSourceSelect();

public slots:

signals:
void addRasterLayer( QString const & rasterLayerPath,
QString const & baseName,
QString const & providerKey );

private:
QgsWcsCapabilities mCapabilities;

QString selectedIdentifier();

// QgsWcsCapabilities virtual methods
void populateLayerList( );
void addClicked();
void on_mLayersTreeWidget_itemSelectionChanged();
void enableLayersForCrs( QTreeWidgetItem *item );
void updateButtons();
QList<QgsOWSSupportedFormat> providerFormats();
QStringList selectedLayersFormats();
QStringList selectedLayersCRSs();
};
#endif // QGSWCSSOURCESELECT_H


26 changes: 26 additions & 0 deletions src/providers/ows/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
SET(OWS_SRCS
qgsowsprovider.cpp
qgsowsdataitems.cpp
)
SET(OWS_MOC_HDRS
qgsowsprovider.h
qgsowsdataitems.h
)

INCLUDE_DIRECTORIES (
../../core
../../gui
${CMAKE_CURRENT_BINARY_DIR}/../../ui
)

QT4_WRAP_CPP(OWS_MOC_SRCS ${OWS_MOC_HDRS})
ADD_LIBRARY (owsprovider MODULE ${OWS_SRCS} ${OWS_MOC_SRCS})

TARGET_LINK_LIBRARIES (owsprovider
qgis_core
qgis_gui
)

INSTALL(TARGETS owsprovider
RUNTIME DESTINATION ${QGIS_PLUGIN_DIR}
LIBRARY DESTINATION ${QGIS_PLUGIN_DIR})
239 changes: 239 additions & 0 deletions src/providers/ows/qgsowsdataitems.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#include "qgsproviderregistry.h"
#include "qgsowsdataitems.h"
#include "qgsowsprovider.h"
#include "qgslogger.h"
#include "qgsdatasourceuri.h"
//#include "qgsowssourceselect.h"
#include "qgsowsconnection.h"
#include "qgsnewhttpconnection.h"

#include <QFileInfo>

// ---------------------------------------------------------------------------
QgsOWSConnectionItem::QgsOWSConnectionItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) );
}

QgsOWSConnectionItem::~QgsOWSConnectionItem()
{
}

QVector<QgsDataItem*> QgsOWSConnectionItem::createChildren()
{
QgsDebugMsg( "Entered" );
QVector<QgsDataItem*> children;

QVector<QgsDataItem*> serviceItems;

int layerCount;
// Try to open with WMS,WFS,WCS
foreach( QString key, QStringList() << "wms" << "WFS" << "gdal" )
{
QgsDebugMsg( "Add connection for provider " + key );
QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( key );
if ( !library ) continue;

dataItem_t * dItem = ( dataItem_t * ) cast_to_fptr( library->resolve( "dataItem" ) );
if ( !dItem )
{
QgsDebugMsg( library->fileName() + " does not have dataItem" );
continue;
}

QgsDataItem *item = dItem( mPath, this ); // empty path -> top level
if ( !item ) continue;

layerCount += item->rowCount();
if ( item->rowCount() > 0 )
{
QgsDebugMsg( "Add new item : " + item->name() );
serviceItems.append( item );
}
else
{
//delete item;
}
}

foreach( QgsDataItem* item, serviceItems )
{
QgsDebugMsg( QString( "serviceItems.size = %1 layerCount = %2 rowCount = %3" ).arg( serviceItems.size() ).arg( layerCount ).arg( item->rowCount() ) );
if ( serviceItems.size() == 1 || layerCount <= 30 || item->rowCount() <= 10 )
{
// Add layers directly to OWS connection
foreach( QgsDataItem* subItem, item->children() )
{
item->removeChildItem( subItem );
subItem->setParent( this );
children.append( subItem );
}
delete item;
}
else // Add service
{
children.append( item );
}
}

return children;
}

bool QgsOWSConnectionItem::equal( const QgsDataItem *other )
{
if ( type() != other->type() )
{
return false;
}
const QgsOWSConnectionItem *o = dynamic_cast<const QgsOWSConnectionItem *>( other );
return ( mPath == o->mPath && mName == o->mName );
}

QList<QAction*> QgsOWSConnectionItem::actions()
{
QList<QAction*> lst;

QAction* actionEdit = new QAction( tr( "Edit..." ), this );
connect( actionEdit, SIGNAL( triggered() ), this, SLOT( editConnection() ) );
lst.append( actionEdit );

QAction* actionDelete = new QAction( tr( "Delete" ), this );
connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteConnection() ) );
lst.append( actionDelete );

return lst;
}

void QgsOWSConnectionItem::editConnection()
{
/*
QgsNewHttpConnection nc( 0, "/Qgis/connections-ows/", mName );
if ( nc.exec() )
{
// the parent should be updated
mParent->refresh();
}
*/
}

void QgsOWSConnectionItem::deleteConnection()
{
/*
QgsOWSConnection::deleteConnection( "OWS", mName );
// the parent should be updated
mParent->refresh();
*/
}


// ---------------------------------------------------------------------------


QgsOWSRootItem::QgsOWSRootItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mIcon = QIcon( getThemePixmap( "mIconOws.png" ) );

populate();
}

QgsOWSRootItem::~QgsOWSRootItem()
{
}

QVector<QgsDataItem*>QgsOWSRootItem::createChildren()
{
QgsDebugMsg( "Entered" );
QVector<QgsDataItem*> connections;
// Combine all WMS,WFS,WCS connections
QMap<QString, QStringList> uris;
foreach( QString service, QStringList() << "WMS" << "WFS" << "WCS" )
{
foreach( QString connName, QgsOWSConnection::connectionList( service ) )
{
QgsOWSConnection connection( service, connName );

QString encodedUri = connection.uri().encodedUri();
QStringList labels = uris.value( encodedUri );
if ( !labels.contains( connName ) )
{
labels << connName;
}
uris[encodedUri] = labels;
}
}
foreach( QString encodedUri, uris.keys() )
{
QgsDataItem * conn = new QgsOWSConnectionItem( this, uris.value( encodedUri ).join( " / " ), encodedUri );
connections.append( conn );
}
return connections;
}

QList<QAction*> QgsOWSRootItem::actions()
{
QList<QAction*> lst;

/*
QAction* actionNew = new QAction( tr( "New Connection..." ), this );
connect( actionNew, SIGNAL( triggered() ), this, SLOT( newConnection() ) );
lst.append( actionNew );
*/
return lst;
}


QWidget * QgsOWSRootItem::paramWidget()
{
/*
QgsOWSSourceSelect *select = new QgsOWSSourceSelect( 0, 0, true, true );
connect( select, SIGNAL( connectionsChanged() ), this, SLOT( connectionsChanged() ) );
return select;
*/
return 0;
}
void QgsOWSRootItem::connectionsChanged()
{
refresh();
}

void QgsOWSRootItem::newConnection()
{
/*
QgsNewHttpConnection nc( 0, "/Qgis/connections-ows/" );
if ( nc.exec() )
{
refresh();
}
*/
}


// ---------------------------------------------------------------------------

static QStringList extensions = QStringList();
static QStringList wildcards = QStringList();

QGISEXTERN int dataCapabilities()
{
return QgsDataProvider::Net;
}

QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
{
if ( thePath.isEmpty() )
{
return new QgsOWSRootItem( parentItem, "OWS", "ows:" );
}

}

//QGISEXTERN QgsOWSSourceSelect * selectWidget( QWidget * parent, Qt::WFlags fl )
QGISEXTERN QDialog * selectWidget( QWidget * parent, Qt::WFlags fl )
{
//return new QgsOWSSourceSelect( parent, fl );
return 0;
}
42 changes: 42 additions & 0 deletions src/providers/ows/qgsowsdataitems.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef QGSOWSDATAITEMS_H
#define QGSOWSDATAITEMS_H

#include "qgsdataitem.h"
#include "qgsdatasourceuri.h"
class QgsOWSConnectionItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsOWSConnectionItem( QgsDataItem* parent, QString name, QString path );
~QgsOWSConnectionItem();

QVector<QgsDataItem*> createChildren();
virtual bool equal( const QgsDataItem *other );

virtual QList<QAction*> actions();

public slots:
void editConnection();
void deleteConnection();
};

class QgsOWSRootItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsOWSRootItem( QgsDataItem* parent, QString name, QString path );
~QgsOWSRootItem();

QVector<QgsDataItem*> createChildren();

virtual QList<QAction*> actions();

virtual QWidget * paramWidget();

public slots:
void connectionsChanged();

void newConnection();
};

#endif // QGSOWSDATAITEMS_H
65 changes: 65 additions & 0 deletions src/providers/ows/qgsowsprovider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/***************************************************************************
qgsowsprovider.cpp - OWS meta provider for WMS,WFS,WCS in browser
-------------------
begin : 4/2012
copyright : (C) 2010 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgslogger.h"
#include "qgsowsprovider.h"
#include "qgsconfig.h"

#include <QString>

static QString PROVIDER_KEY = "ows";
static QString PROVIDER_DESCRIPTION = "OWS meta provider";

QgsOwsProvider::QgsOwsProvider( QString const & uri )
: QgsDataProvider( uri )
{
}

QgsOwsProvider::~QgsOwsProvider()
{
}

QGISEXTERN QgsOwsProvider * classFactory( const QString *uri )
{
return new QgsOwsProvider( *uri );
}

QString QgsOwsProvider::name() const
{
return PROVIDER_KEY;
}

QString QgsOwsProvider::description() const
{
return PROVIDER_DESCRIPTION;
}

QGISEXTERN QString providerKey()
{
return PROVIDER_KEY;
}

QGISEXTERN QString description()
{
return PROVIDER_DESCRIPTION;
}

QGISEXTERN bool isProvider()
{
return true;
}

66 changes: 66 additions & 0 deletions src/providers/ows/qgsowsprovider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/***************************************************************************
qgsowsprovider.h - OWS meta provider for WMS,WFS,WCS in browser
-------------------
begin : 4/2012
copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSOWSPROVIDER_H
#define QGSOWSPROVIDER_H

#include "qgsdataprovider.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsdataitem.h"
#include "qgsrectangle.h"

#include <QString>

/**
\brief Data provider for GDAL layers.
This provider implements the interface defined in the QgsDataProvider class
to provide access to spatial data residing in a GDAL layers.
*/
class QgsOwsProvider : public QgsDataProvider
{
Q_OBJECT

public:
/**
* Constructor for the provider.
*
* \param uri HTTP URL of the Web Server. If needed a proxy will be used
* otherwise we contact the host directly.
*
*/
QgsOwsProvider( QString const & uri = 0 );

//! Destructor
~QgsOwsProvider();

/* Pure virtuals */

QString name() const;

QString description() const;

QgsCoordinateReferenceSystem crs() { return QgsCoordinateReferenceSystem(); }

QgsRectangle extent() { return QgsRectangle(); }

bool isValid() { return false; }
};

#endif // QGSOWSPROVIDER_H
4 changes: 2 additions & 2 deletions src/providers/wfs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

SET(WFS_SRCS
qgswfsprovider.cpp
qgswfsconnection.cpp
qgswfscapabilities.cpp
qgswfsdataitems.cpp
qgswfsdata.cpp
qgswfssourceselect.cpp
Expand All @@ -13,7 +13,7 @@ SET(WFS_SRCS

SET (WFS_MOC_HDRS
qgswfsdata.h
qgswfsconnection.h
qgswfscapabilities.h
qgswfsdataitems.h
qgswfsprovider.h
qgswfssourceselect.h
Expand Down
Loading