From 13bbb6017154445efae932cdfe1dcfc8128176fa Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 25 Apr 2012 18:32:54 +0200 Subject: [PATCH 01/19] OWS common classes --- src/core/qgsowsconnection.cpp | 187 ++++++ src/core/qgsowsconnection.h | 75 +++ src/gui/qgsowssourceselect.cpp | 1012 ++++++++++++++++++++++++++++++ src/gui/qgsowssourceselect.h | 236 +++++++ src/ui/qgsowssourceselectbase.ui | 502 +++++++++++++++ 5 files changed, 2012 insertions(+) create mode 100644 src/core/qgsowsconnection.cpp create mode 100644 src/core/qgsowsconnection.h create mode 100644 src/gui/qgsowssourceselect.cpp create mode 100644 src/gui/qgsowssourceselect.h create mode 100644 src/ui/qgsowssourceselectbase.ui diff --git a/src/core/qgsowsconnection.cpp b/src/core/qgsowsconnection.cpp new file mode 100644 index 00000000000..f3f38828771 --- /dev/null +++ b/src/core/qgsowsconnection.cpp @@ -0,0 +1,187 @@ +/*************************************************************************** + 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 , 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 +//#include +//#include +//#include +//#include +//#include +#include +//#include +#include +#include +#include +#include + +#include +#include + +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(); + if ( ignoreGetMap || ignoreGetFeatureInfo ) + { + QString connArgs = "ignoreUrl="; + if ( ignoreGetMap ) + { + connArgs += "GetMap"; + if ( ignoreGetFeatureInfo ) + connArgs += ";"; + mUri.setParam( "ignoreUrl", "GetMap" ); + } + if ( ignoreGetFeatureInfo ) + { + connArgs += "GetFeatureInfo"; + mUri.setParam( "ignoreUrl", "GetFeatureInfo" ); + } + if ( mConnectionInfo.startsWith( "username=" ) ) + { + mConnectionInfo.prepend( connArgs + "," ); + } + else + { + mConnectionInfo.prepend( connArgs + ",url=" ); + } + } + + 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 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 ); +} diff --git a/src/core/qgsowsconnection.h b/src/core/qgsowsconnection.h new file mode 100644 index 00000000000..f768fd58144 --- /dev/null +++ b/src/core/qgsowsconnection.h @@ -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 , 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 +#include + +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 diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp new file mode 100644 index 00000000000..c12df80786c --- /dev/null +++ b/src/gui/qgsowssourceselect.cpp @@ -0,0 +1,1012 @@ +/*************************************************************************** + qgsowssourceselect.cpp - selector for WMS,WFS,WCS + ------------------- + 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 , Sourcepole AG + wms-c support : (C) 2010 Juergen E. Fischer < jef at norbit dot de >, norBIT GmbH + + generalized : (C) 2012 Radim Blazek, based on qgswmssourceselect.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 "qgis.h" // GEO_EPSG_CRS_ID +#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 "qgsdataprovider.h" +#include "qgsowssourceselect.h" +#include "qgsnetworkaccessmanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QgsOWSSourceSelect::QgsOWSSourceSelect( QString service, QWidget * parent, Qt::WFlags fl, bool managerMode, bool embeddedMode ) + : QDialog( parent, fl ) + , mService ( service ) + , mManagerMode( managerMode ) + , mEmbeddedMode( embeddedMode ) + , mCurrentTileset( 0 ) +{ + setupUi( this ); + + if ( mEmbeddedMode ) + { + mDialogButtonBox->button( QDialogButtonBox::Close )->hide(); + } + + mAddButton = mDialogButtonBox->button( QDialogButtonBox::Apply ); + mAddButton->setText( tr( "&Add" ) ); + mAddButton->setToolTip( tr( "Add selected layers to map" ) ); + mAddButton->setEnabled( false ); + + mTileWidthLineEdit->setValidator( new QIntValidator( 0, 9999, this ) ); + mTileHeightLineEdit->setValidator( new QIntValidator( 0, 9999, this ) ); + mFeatureCountLineEdit->setValidator( new QIntValidator( 0, 9999, this ) ); + + mImageFormatGroup = new QButtonGroup; + + if ( !mManagerMode ) + { + connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addClicked() ) ); + //set the current project CRS if available + long currentCRS = QgsProject::instance()->readNumEntry( "SpatialRefSys", "/ProjectCRSID", -1 ); + if ( currentCRS != -1 ) + { + //convert CRS id to epsg + QgsCoordinateReferenceSystem currentRefSys( currentCRS, QgsCoordinateReferenceSystem::InternalCrsId ); + if ( currentRefSys.isValid() ) + { + mCRS = currentRefSys.authid(); + } + } + + // set up the default WMS Coordinate Reference System + //mCRSLabel->setText( descriptionForAuthId( mCRS ) ); + } + else + { + mTabWidget->removeTab( mTabWidget->indexOf( mLayerOrderTab ) ); + mTabWidget->removeTab( mTabWidget->indexOf( mTilesetsTab ) ); + mImageFormatsGroupBox->hide(); + mLayersTab->layout()->removeWidget( mImageFormatsGroupBox ); + mCRSGroupBox->hide(); + mLayersTab->layout()->removeWidget( mCRSGroupBox ); + mAddButton->hide(); + } + + // set up the WMS connections we already know about + populateConnectionList(); + + QSettings settings; + QgsDebugMsg( "restoring geometry" ); + restoreGeometry( settings.value( "/Windows/WMSSourceSelect/geometry" ).toByteArray() ); +} + +QgsOWSSourceSelect::~QgsOWSSourceSelect() +{ + QSettings settings; + QgsDebugMsg( "saving geometry" ); + settings.setValue( "/Windows/WMSSourceSelect/geometry", saveGeometry() ); +} + +void QgsOWSSourceSelect::populateFormats() +{ + QgsDebugMsg ( "entered"); + if ( mProviderFormats.size() == 0 ) + { + QHBoxLayout *layout = new QHBoxLayout; + + mProviderFormats = providerFormats(); + + // add buttons for available formats + for ( int i = 0; i < mProviderFormats.size(); i++ ) + { + mMimeMap.insert( mProviderFormats[i].format, i ); + + QRadioButton *btn = new QRadioButton( mProviderFormats[i].label ); + btn->setToolTip( mProviderFormats[i].format ); + mImageFormatGroup->addButton( btn, i ); + layout->addWidget( btn ); + } + + // default to first encoding + /* + if ( mImageFormatGroup->buttons().size() > 0 ) + { + mImageFormatGroup->button( 0 )->setChecked( true ); + } + */ + //mImageFormatsGroupBox->setDisabled( true ); + + layout->addStretch(); + mImageFormatsGroupBox->setLayout( layout ); + } + // Show supported by server only + + foreach( QAbstractButton *b, mImageFormatGroup->buttons() ) + { + b->setHidden( true ); + } + + int firstVisible = -1; + foreach( QString encoding, serverFormats() ) + { + QgsDebugMsg( "server format = " + encoding ); + int id = mMimeMap.value( encoding, -1 ); + if ( id < 0 ) + { + QgsDebugMsg( QString( "encoding %1 not supported." ).arg( encoding ) ); + continue; + } + + mImageFormatGroup->button( id )->setVisible( true ); + if ( firstVisible == -1 ) firstVisible = id; + } + // Set first if no one visible is checked + if ( !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() && firstVisible > -1 ) + { + mImageFormatGroup->button( firstVisible )->setChecked(true); + } + + mImageFormatsGroupBox->setEnabled( true ); +} + +void QgsOWSSourceSelect::populateConnectionList() +{ + mConnectionsComboBox->clear(); + mConnectionsComboBox->addItems( QgsOWSConnection::connectionList(mService) ); + + setConnectionListPosition(); + + if ( mConnectionsComboBox->count() == 0 ) + { + // No connections - disable various buttons + mConnectButton->setEnabled( false ); + mEditButton->setEnabled( false ); + mDeleteButton->setEnabled( false ); + } + else + { + // Connections - enable various buttons + mConnectButton->setEnabled( true ); + mEditButton->setEnabled( true ); + mDeleteButton->setEnabled( true ); + } +} +void QgsOWSSourceSelect::on_mNewButton_clicked() +{ + QgsNewHttpConnection *nc = new QgsNewHttpConnection( this, "/Qgis/connections-" + mService.toLower() + "/" ); + + if ( nc->exec() ) + { + populateConnectionList(); + emit connectionsChanged(); + } + + delete nc; +} + +void QgsOWSSourceSelect::on_mEditButton_clicked() +{ + QgsNewHttpConnection *nc = new QgsNewHttpConnection( this, "/Qgis/connections-" + mService.toLower() + "/", mConnectionsComboBox->currentText() ); + + if ( nc->exec() ) + { + populateConnectionList(); + emit connectionsChanged(); + } + + delete nc; +} + +void QgsOWSSourceSelect::on_mDeleteButton_clicked() +{ + QString msg = tr( "Are you sure you want to remove the %1 connection and all associated settings?" ) + .arg( mConnectionsComboBox->currentText() ); + QMessageBox::StandardButton result = QMessageBox::information( this, tr( "Confirm Delete" ), msg, QMessageBox::Ok | QMessageBox::Cancel ); + if ( result == QMessageBox::Ok ) + { + QgsOWSConnection::deleteConnection( mService, mConnectionsComboBox->currentText() ); + mConnectionsComboBox->removeItem( mConnectionsComboBox->currentIndex() ); // populateConnectionList(); + setConnectionListPosition(); + emit connectionsChanged(); + } +} + +void QgsOWSSourceSelect::on_mSaveButton_clicked() +{ + QgsManageConnectionsDialog dlg( this, QgsManageConnectionsDialog::Export, QgsManageConnectionsDialog::WMS ); + dlg.exec(); +} + +void QgsOWSSourceSelect::on_mLoadButton_clicked() +{ + QString fileName = QFileDialog::getOpenFileName( this, tr( "Load connections" ), ".", + tr( "XML files (*.xml *XML)" ) ); + if ( fileName.isEmpty() ) + { + return; + } + + QgsManageConnectionsDialog dlg( this, QgsManageConnectionsDialog::Import, QgsManageConnectionsDialog::WMS, fileName ); + dlg.exec(); + populateConnectionList(); + emit connectionsChanged(); +} + +QgsNumericSortTreeWidgetItem *QgsOWSSourceSelect::createItem( + int id, + const QStringList &names, + QMap &items, + int &layerAndStyleCount, + const QMap &layerParents, + const QMap &layerParentNames ) +{ + QgsDebugMsg( QString( "id = %1 layerAndStyleCount = %2 names = %3 ").arg( id).arg(layerAndStyleCount).arg(names.join(",") ) ); + if ( items.contains( id ) ) + return items[id]; + + + QgsNumericSortTreeWidgetItem *item; + if ( layerParents.contains( id ) ) + { + // it has parent -> create first its parent + int parent = layerParents[ id ]; + item = new QgsNumericSortTreeWidgetItem( createItem( parent, layerParentNames[ parent ], items, layerAndStyleCount, layerParents, layerParentNames ) ); + } + else + item = new QgsNumericSortTreeWidgetItem( mLayersTreeWidget ); + + item->setText( 0, QString::number( ++layerAndStyleCount ) ); + item->setText( 1, names[0].simplified() ); + item->setText( 2, names[1].simplified() ); + item->setText( 3, names[2].simplified() ); + item->setToolTip( 3, "" + names[2].simplified() + "" ); + + items[ id ] = item; + + return item; +} + +bool QgsOWSSourceSelect::populateLayerList( ) +{ + return true; +} + +void QgsOWSSourceSelect::on_mConnectButton_clicked() +{ + QgsDebugMsg( "entered" ); + mConnName = mConnectionsComboBox->currentText(); + + QgsOWSConnection connection( mService, mConnectionsComboBox->currentText() ); + //QgsDataProvider *theProvider = connection.provider( ); + mConnectionInfo = connection.connectionInfo(); + mUri = connection.uri(); + + QApplication::setOverrideCursor( Qt::WaitCursor ); + + QgsDebugMsg( "call populateLayerList" ); + if ( !populateLayerList() ) + { + //showError( theProvider ); + } + + QApplication::restoreOverrideCursor(); +} + +void QgsOWSSourceSelect::addClicked() +{ + QgsDebugMsg( "entered"); +/* + QStringList layers; + QStringList styles; + QString format; + QString crs; + + QgsDataSourceURI uri = mUri; + + if ( mTilesetsTableWidget->selectedItems().isEmpty() ) + { + collectSelectedLayers( layers, styles ); + crs = mCRS; + //format = mProviderFormats[ mImageFormatGroup->checkedId()].format; + + if ( mTileWidthLineEdit->text().toInt() > 0 && mTileHeightLineEdit->text().toInt() > 0 ) + { + uri.setParam( "tileWidth", mTileWidthLineEdit->text() ); + uri.setParam( "tileHeight", mTileHeightLineEdit->text() ); + } + } + else + { + QTableWidgetItem *item = mTilesetsTableWidget->selectedItems().first(); + layers = item->data( Qt::UserRole + 0 ).toStringList(); + styles = item->data( Qt::UserRole + 1 ).toStringList(); + format = item->data( Qt::UserRole + 2 ).toString(); + crs = item->data( Qt::UserRole + 3 ).toString(); + + uri.setParam( "tileWidth", item->data( Qt::UserRole + 4 ).toString() ); + uri.setParam( "tileHeight", item->data( Qt::UserRole + 5 ).toString() ); + uri.setParam( "tileResolutions", item->data( Qt::UserRole + 6 ).toStringList() ); + } + uri.setParam( "layers", layers ); + uri.setParam( "styles", styles ); + //uri.setParam( "format", format ); + uri.setParam( "crs", crs ); + + if ( mFeatureCountLineEdit->text().toInt() > 0 ) + { + uri.setParam( "featureCount", mFeatureCountLineEdit->text() ); + } + + QgsDebugMsg( "crs = " + crs ); + + QgsDebugMsg( "uri = " + uri.encodedUri() ); + + // TODO + QString providerKey = "gdal"; + emit addRasterLayer( uri.encodedUri(), + mLayerNameLineEdit->text().isEmpty() ? layers.join( "/" ) : mLayerNameLineEdit->text(), + providerKey ); +*/ +} + +void QgsOWSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item ) +{ +/* + QString layerName = item->data( 0, Qt::UserRole + 0 ).toString(); + QString styleName = item->data( 0, Qt::UserRole + 1 ).toString(); + + if ( !layerName.isEmpty() && styleName.isEmpty() ) + { + // layer + bool disable = !item->data( 0, Qt::UserRole + 2 ).toStringList().contains( mCRS, Qt::CaseInsensitive ); + + item->setDisabled( disable ); + + // propagate to styles + for ( int i = 0; i < item->childCount(); i++ ) + { + item->child( i )->setDisabled( disable ); + } + } + else + { + // recurse to child layers + for ( int i = 0; i < item->childCount(); i++ ) + { + enableLayersForCrs( item->child( i ) ); + } + } +*/ +} + +void QgsOWSSourceSelect::on_mChangeCRSButton_clicked() +{ + QStringList layers; + foreach( QTreeWidgetItem *item, mLayersTreeWidget->selectedItems() ) + { + QString layer = item->data( 0, Qt::UserRole + 0 ).toString(); + if ( !layer.isEmpty() ) + layers << layer; + } + + QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector( this ); + mySelector->setMessage(); + mySelector->setOgcWmsCrsFilter( mCRSs ); + + QString myDefaultCrs = QgsProject::instance()->readEntry( "SpatialRefSys", "/ProjectCrs", GEO_EPSG_CRS_AUTHID ); + QgsCoordinateReferenceSystem defaultCRS; + if ( defaultCRS.createFromOgcWmsCrs( myDefaultCrs ) ) + { + mySelector->setSelectedCrsId( defaultCRS.srsid() ); + } + + if ( !mySelector->exec() ) + return; + + mCRS = mySelector->selectedAuthId(); + delete mySelector; + + mCRSLabel->setText( descriptionForAuthId( mCRS ) ); + + for ( int i = 0; i < mLayersTreeWidget->topLevelItemCount(); i++ ) + { + enableLayersForCrs( mLayersTreeWidget->topLevelItem( i ) ); + } + + // TODO + //updateButtons(); + + // update the display of this widget + update(); +} + +void QgsOWSSourceSelect::applySelectionConstraints( QTreeWidgetItem *item ) +{ + if ( item->childCount() == 0 ) + { + return; + } + + int styles = 0; + for ( int i = 0; i < item->childCount(); i++ ) + { + QTreeWidgetItem *child = item->child( i ); + QString style = child->data( 0, Qt::UserRole + 1 ).toString(); + if ( !style.isEmpty() ) + styles++; + } + + if ( styles > 0 ) + { + if ( styles < item->childCount() ) + { + return; + } + + QTreeWidgetItem *style = 0; + QTreeWidgetItem *firstNewStyle = 0; + for ( int i = 0; i < item->childCount(); i++ ) + { + QTreeWidgetItem *child = item->child( i ); + if ( child->isSelected() ) + { + if ( !firstNewStyle && !mCurrentSelection.contains( child ) ) + firstNewStyle = child; + + if ( !style ) + style = child; + + child->setSelected( false ); + } + } + + if ( firstNewStyle || style ) + { + // individual style selected => unselect layer and all parent groups + QTreeWidgetItem *parent = item; + while ( parent ) + { + parent->setSelected( false ); + parent = parent->parent(); + } + + if ( firstNewStyle ) + firstNewStyle->setSelected( true ); + else if ( style ) + style->setSelected( true ); + } + } + else + { + // no styles => layer or layer group => + // process child layers and style selection first + // then + // if some child layers are selected, deselect the group and all parents + // otherwise keep the selection state of the group + int n = 0; + for ( int i = 0; i < item->childCount(); i++ ) + { + QTreeWidgetItem *child = item->child( i ); + applySelectionConstraints( child ); + if ( child->isSelected() ) + n++; + } + + if ( n > 0 ) + { + if ( item->isSelected() ) + { + for ( int i = 0; i < n; i++ ) + { + QTreeWidgetItem *child = item->child( i ); + child->setSelected( false ); + } + item->setExpanded( false ); + } + else + { + for ( QTreeWidgetItem *parent = item->parent(); parent; parent = parent->parent() ) + { + parent->setSelected( false ); + } + } + } + } +} + +void QgsOWSSourceSelect::collectNamedLayers( QTreeWidgetItem *item, QStringList &layers, QStringList &styles ) +{ + QString layerName = item->data( 0, Qt::UserRole + 0 ).toString(); + QString styleName = item->data( 0, Qt::UserRole + 1 ).toString(); + if ( layerName.isEmpty() ) + { + // layer group + for ( int i = 0; i < item->childCount(); i++ ) + collectNamedLayers( item->child( i ), layers, styles ); + } + else if ( styleName.isEmpty() ) + { + // named layers + layers << layerName; + styles << ""; + + if ( mCRSs.isEmpty() ) + mCRSs = item->data( 0, Qt::UserRole + 2 ).toStringList().toSet(); + else + mCRSs.intersect( item->data( 0, Qt::UserRole + 2 ).toStringList().toSet() ); + } +} + +/** + * retrieve selected layers + */ +void QgsOWSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged() +{ + QgsDebugMsg ( "entered"); + mLayersTreeWidget->blockSignals( true ); + for ( int i = 0; i < mLayersTreeWidget->topLevelItemCount(); i++ ) + { + applySelectionConstraints( mLayersTreeWidget->topLevelItem( i ) ); + } + mCurrentSelection = mLayersTreeWidget->selectedItems(); + mLayersTreeWidget->blockSignals( false ); + + + // selected layers with styles + QStringList layers; + QStringList styles; + + mCRSs.clear(); + + // determine selected layers and styles and set of crses that are available for all layers + foreach( QTreeWidgetItem *item, mLayersTreeWidget->selectedItems() ) + { + QString layerName = item->data( 0, Qt::UserRole + 0 ).toString(); + QString styleName = item->data( 0, Qt::UserRole + 1 ).toString(); + + if ( layerName.isEmpty() ) + { + // layers groups: collect named layers of group and add using the default style + collectNamedLayers( item, layers, styles ); + } + else if ( styleName.isEmpty() ) + { + // named layer: add using default style + layers << layerName; + styles << ""; + if ( mCRSs.isEmpty() ) + mCRSs = item->data( 0, Qt::UserRole + 2 ).toStringList().toSet(); + else + mCRSs.intersect( item->data( 0, Qt::UserRole + 2 ).toStringList().toSet() ); + } + else + { + // style: add named layer with selected style + layers << layerName; + styles << styleName; + if ( mCRSs.isEmpty() ) + mCRSs = item->parent()->data( 0, Qt::UserRole + 2 ).toStringList().toSet(); + else + mCRSs.intersect( item->parent()->data( 0, Qt::UserRole + 2 ).toStringList().toSet() ); + } + } + + updateButtons(); +} + +void QgsOWSSourceSelect::populateCRS() +{ + mCRSs = serverCRS().toSet(); + //mCRSGroupBox->setTitle( tr( "Options (%n coordinate reference systems available)", "crs count", mCRSs.count() ) ); + mCRSGroupBox->setTitle( tr( "Coordinate Reference System (%n available)", "crs count", mCRSs.count() ) ); + + mChangeCRSButton->setDisabled( mCRSs.isEmpty() ); + + if ( !mCRSs.isEmpty() ) + { + // check whether current CRS is supported + // if not, use one of the available CRS + QString defaultCRS; + QSet::const_iterator it = mCRSs.begin(); + for ( ; it != mCRSs.end(); it++ ) + { + if ( it->compare( mCRS, Qt::CaseInsensitive ) == 0 ) + break; + + // save first CRS in case the current CRS is not available + if ( it == mCRSs.begin() ) + defaultCRS = *it; + + // prefer value of DEFAULT_GEO_EPSG_CRS_ID if available + if ( *it == GEO_EPSG_CRS_AUTHID ) + defaultCRS = *it; + } + + if ( it == mCRSs.end() ) + { + // not found + mCRS = defaultCRS; + mCRSLabel->setText( descriptionForAuthId( mCRS ) ); + } + + } + else + { + mCRS = ""; + mCRSLabel->setText( "" ); + } + mChangeCRSButton->setEnabled( !mCRSs.isEmpty() ); +} + +void QgsOWSSourceSelect::on_mTilesetsTableWidget_itemClicked( QTableWidgetItem *item ) +{ + Q_UNUSED( item ); + + QTableWidgetItem *rowItem = mTilesetsTableWidget->item( mTilesetsTableWidget->currentRow(), 0 ); + bool wasSelected = mCurrentTileset == rowItem; + + mTilesetsTableWidget->blockSignals( true ); + mTilesetsTableWidget->clearSelection(); + if ( !wasSelected ) + { + QgsDebugMsg( QString( "selecting current row %1" ).arg( mTilesetsTableWidget->currentRow() ) ); + mTilesetsTableWidget->selectRow( mTilesetsTableWidget->currentRow() ); + mCurrentTileset = rowItem; + } + else + { + mCurrentTileset = 0; + } + mTilesetsTableWidget->blockSignals( false ); + + updateButtons(); +} + + + +QString QgsOWSSourceSelect::connName() +{ + return mConnName; +} + +QString QgsOWSSourceSelect::connectionInfo() +{ + return mConnectionInfo; +} + +QString QgsOWSSourceSelect::selectedFormat() +{ + // TODO: Match this hard coded list to the list of formats Qt reports it can actually handle. + int id = mImageFormatGroup->checkedId(); + if ( id < 0 ) + { + return ""; + } + else + { + // TODO: do encoding in subclass (WMS) + //return QUrl::toPercentEncoding( mProviderFormats[ id ].format ); + return mProviderFormats[ id ].format; + } +} + +QString QgsOWSSourceSelect::selectedCrs() +{ + return mCRS; +} + +void QgsOWSSourceSelect::setConnectionListPosition() +{ + QString toSelect = QgsOWSConnection::selectedConnection( mService ); + + mConnectionsComboBox->setCurrentIndex( mConnectionsComboBox->findText( toSelect ) ); + + if ( mConnectionsComboBox->currentIndex() < 0 ) + { + if ( toSelect.isNull() ) + mConnectionsComboBox->setCurrentIndex( 0 ); + else + mConnectionsComboBox->setCurrentIndex( mConnectionsComboBox->count() - 1 ); + } + QgsOWSConnection::setSelectedConnection( mService, mConnectionsComboBox->currentText() ); +} + +void QgsOWSSourceSelect::showStatusMessage( QString const &theMessage ) +{ + mStatusLabel->setText( theMessage ); + + // update the display of this widget + update(); +} + + +void QgsOWSSourceSelect::showError( QString const &theTitle, QString const &theFormat, QString const &theError ) +{ + QgsMessageViewer * mv = new QgsMessageViewer( this ); + mv->setWindowTitle( theTitle ); + + if ( theFormat == "text/html" ) + { + mv->setMessageAsHtml( theError ); + } + else + { + mv->setMessageAsPlainText( tr( "Could not understand the response:\n%1" ).arg( theError) ); + } + mv->showMessage( true ); // Is deleted when closed +} + +void QgsOWSSourceSelect::on_mConnectionsComboBox_activated( int ) +{ + // Remember which server was selected. + QgsOWSConnection::setSelectedConnection( mService, mConnectionsComboBox->currentText() ); +} + +void QgsOWSSourceSelect::on_mAddDefaultButton_clicked() +{ + addDefaultServers(); +} + +QString QgsOWSSourceSelect::descriptionForAuthId( QString authId ) +{ + if ( mCrsNames.contains( authId ) ) + return mCrsNames[ authId ]; + + QgsCoordinateReferenceSystem qgisSrs; + qgisSrs.createFromOgcWmsCrs( authId ); + mCrsNames.insert( authId, qgisSrs.description() ); + return qgisSrs.description(); +} + +void QgsOWSSourceSelect::addDefaultServers() +{ + QMap exampleServers; + exampleServers["DM Solutions GMap"] = "http://www2.dmsolutions.ca/cgi-bin/mswms_gmap"; + exampleServers["Lizardtech server"] = "http://wms.lizardtech.com/lizardtech/iserv/ows"; + // Nice to have the qgis users map, but I'm not sure of the URL at the moment. + // exampleServers["Qgis users map"] = "http://qgis.org/wms.cgi"; + + QSettings settings; + settings.beginGroup( "/Qgis/connections-" + mService.toLower() ); + QMap::const_iterator i = exampleServers.constBegin(); + for ( ; i != exampleServers.constEnd(); ++i ) + { + // Only do a server if it's name doesn't already exist. + QStringList keys = settings.childGroups(); + if ( !keys.contains( i.key() ) ) + { + QString path = i.key(); + settings.setValue( path + "/url", i.value() ); + } + } + settings.endGroup(); + populateConnectionList(); + + QMessageBox::information( this, tr( "WMS proxies" ), "

" + tr( "Several WMS servers have " + "been added to the server list. Note that if " + "you access the internet via a web proxy, you will " + "need to set the proxy settings in the QGIS options dialog." ) + "

" ); +} + +void QgsOWSSourceSelect::addWMSListRow( const QDomElement& item, int row ) +{ + QDomElement title = item.firstChildElement( "title" ); + addWMSListItem( title, row, 0 ); + QDomElement description = item.firstChildElement( "description" ); + addWMSListItem( description, row, 1 ); + QDomElement link = item.firstChildElement( "link" ); + addWMSListItem( link, row, 2 ); +} + +void QgsOWSSourceSelect::addWMSListItem( const QDomElement& el, int row, int column ) +{ + if ( !el.isNull() ) + { + QTableWidgetItem* tableItem = new QTableWidgetItem( el.text() ); + // TODO: add linebreaks to long tooltips? + tableItem->setToolTip( el.text() ); + mSearchTableWidget->setItem( row, column, tableItem ); + } +} + +void QgsOWSSourceSelect::on_mSearchButton_clicked() +{ + // clear results + mSearchTableWidget->clearContents(); + mSearchTableWidget->setRowCount( 0 ); + + // disable Add WMS button + mSearchAddButton->setEnabled( false ); + + QApplication::setOverrideCursor( Qt::WaitCursor ); + + QSettings settings; + // geopole.org (geopole.ch) 25.4.2012 : 503 Service Unavailable, archive: Recently added 20 Jul 2011 + QString mySearchUrl = settings.value( "/qgis/WMSSearchUrl", "http://geopole.org/wms/search?search=%1&type=rss" ).toString(); + QUrl url( mySearchUrl.arg( mSearchTermLineEdit->text() ) ); + QgsDebugMsg( url.toString() ); + + QNetworkReply *r = QgsNetworkAccessManager::instance()->get( QNetworkRequest( url ) ); + connect( r, SIGNAL( finished() ), SLOT( searchFinished() ) ); +} + +void QgsOWSSourceSelect::searchFinished() +{ + QApplication::restoreOverrideCursor(); + + QNetworkReply *r = qobject_cast( sender() ); + if ( !r ) + return; + + if ( r->error() == QNetworkReply::NoError ) + { + // parse results + QDomDocument doc( "RSS" ); + QByteArray res = r->readAll(); + QString error; + int line, column; + if ( doc.setContent( res, &error, &line, &column ) ) + { + QDomNodeList list = doc.elementsByTagName( "item" ); + mSearchTableWidget->setRowCount( list.size() ); + for ( int i = 0; i < list.size(); i++ ) + { + if ( list.item( i ).isElement() ) + { + QDomElement item = list.item( i ).toElement(); + addWMSListRow( item, i ); + } + } + + mSearchTableWidget->resizeColumnsToContents(); + } + else + { + QgsDebugMsg( "setContent failed" ); + showStatusMessage( tr( "parse error at row %1, column %2: %3" ).arg( line ).arg( column ).arg( error ) ); + } + } + else + { + showStatusMessage( tr( "network error: %1" ).arg( r->error() ) ); + } + + r->deleteLater(); +} + +void QgsOWSSourceSelect::on_mAddWMSButton_clicked() +{ + // TODO: deactivate button if dialog is open? + // TODO: remove from config on close? + + int selectedRow = mSearchTableWidget->currentRow(); + if ( selectedRow == -1 ) + { + return; + } + + QString wmsTitle = mSearchTableWidget->item( selectedRow, 0 )->text(); + QString wmsUrl = mSearchTableWidget->item( selectedRow, 2 )->text(); + + QSettings settings; + if ( settings.contains( QString( "Qgis/connections-wms/%1/url" ).arg( wmsTitle ) ) ) + { + QString msg = tr( "The %1 connection already exists. Do you want to overwrite it?" ).arg( wmsTitle ); + QMessageBox::StandardButton result = QMessageBox::information( this, tr( "Confirm Overwrite" ), msg, QMessageBox::Ok | QMessageBox::Cancel ); + if ( result != QMessageBox::Ok ) + { + return; + } + } + + // add selected WMS to config and mark as current + settings.setValue( QString( "Qgis/connections-wms/%1/url" ).arg( wmsTitle ), wmsUrl ); + QgsOWSConnection::setSelectedConnection( mService, wmsTitle ); + populateConnectionList(); + + mTabWidget->setCurrentIndex( 0 ); +} + +void QgsOWSSourceSelect::on_mSearchTableWidget_itemSelectionChanged() +{ + mSearchAddButton->setEnabled( mSearchTableWidget->currentRow() != -1 ); +} + +void QgsOWSSourceSelect::on_mLayerUpButton_clicked() +{ + QList selectionList = mLayerOrderTreeWidget->selectedItems(); + if ( selectionList.size() < 1 ) + { + return; + } + int selectedIndex = mLayerOrderTreeWidget->indexOfTopLevelItem( selectionList[0] ); + if ( selectedIndex < 1 ) + { + return; //item not existing or already on top + } + + QTreeWidgetItem* selectedItem = mLayerOrderTreeWidget->takeTopLevelItem( selectedIndex ); + mLayerOrderTreeWidget->insertTopLevelItem( selectedIndex - 1, selectedItem ); + mLayerOrderTreeWidget->clearSelection(); + selectedItem->setSelected( true ); +} + +void QgsOWSSourceSelect::on_mLayerDownButton_clicked() +{ + QList selectionList = mLayerOrderTreeWidget->selectedItems(); + if ( selectionList.size() < 1 ) + { + return; + } + int selectedIndex = mLayerOrderTreeWidget->indexOfTopLevelItem( selectionList[0] ); + if ( selectedIndex < 0 || selectedIndex > mLayerOrderTreeWidget->topLevelItemCount() - 2 ) + { + return; //item not existing or already at bottom + } + + QTreeWidgetItem* selectedItem = mLayerOrderTreeWidget->takeTopLevelItem( selectedIndex ); + mLayerOrderTreeWidget->insertTopLevelItem( selectedIndex + 1, selectedItem ); + mLayerOrderTreeWidget->clearSelection(); + selectedItem->setSelected( true ); +} + +QList QgsOWSSourceSelect::providerFormats() +{ + return QList(); +} + +QStringList QgsOWSSourceSelect::serverFormats() +{ + return QStringList(); +} + +QStringList QgsOWSSourceSelect::serverCRS() +{ + return QStringList(); +} + +QStringList QgsOWSSourceSelect::layerCRS( int id ) +{ + Q_UNUSED ( id ); + return QStringList(); +} + +void QgsOWSSourceSelect::updateButtons() +{ +} diff --git a/src/gui/qgsowssourceselect.h b/src/gui/qgsowssourceselect.h new file mode 100644 index 00000000000..49e13db5e11 --- /dev/null +++ b/src/gui/qgsowssourceselect.h @@ -0,0 +1,236 @@ +/*************************************************************************** + 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 , 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 +#include + +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() ); } + + protected: + /** + * List of image formats (encodings) supported by provider + * @return list of format/label pairs + */ + virtual QList providerFormats(); + + //! List of formats supported for currently selected layer item(s) + virtual QStringList serverFormats(); + + //! Server CRS supported for currently selected layer item(s) + virtual QStringList serverCRS(); + + virtual QStringList layerCRS( int id ); + + //! Populate the connection list combo box + void populateConnectionList(); + + //! Populate supported formats + void populateFormats(); + + //! 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; + + //! Selected CRS + QString mCRS; + + //! Common CRSs for selected layers + QSet mCRSs; + + //! Supported formats + QList mProviderFormats; + + //! Map mime types to supported formats + QMap mMimeMap; + + /** + * \brief Populate the layer list - private for now. + * + * \retval false if the layers could not be retrieved or parsed - + * see mWmsProvider->errorString() for more info + */ + virtual bool populateLayerList( ); + + //! create an item including possible parents + QgsNumericSortTreeWidgetItem *createItem( int id, + const QStringList &names, + QMap &items, + int &layerAndStyleCount, + const QMap &layerParents, + const QMap &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 mCrsNames; + + void addWMSListRow( const QDomElement& item, int row ); + void addWMSListItem( const QDomElement& el, int row, int column ); + + void applySelectionConstraints( QTreeWidgetItem *item ); + void collectNamedLayers( QTreeWidgetItem *item, QStringList &layers, QStringList &styles ); + virtual void enableLayersForCrs( QTreeWidgetItem *item ); + + //! Returns currently selected format + QString selectedFormat(); + + //! Returns currently selected Crs + QString selectedCrs(); + + QList mCurrentSelection; + QTableWidgetItem* mCurrentTileset; + + signals: + void addRasterLayer( QString const & rasterLayerPath, + QString const & baseName, + QString const & providerKey ); + void connectionsChanged(); + + protected: + //! Name for selected connection + QString mConnName; + + //! Cnnection info for selected connection + QString mConnectionInfo; + + //! URI for selected connection + QgsDataSourceURI mUri; + + 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 diff --git a/src/ui/qgsowssourceselectbase.ui b/src/ui/qgsowssourceselectbase.ui new file mode 100644 index 00000000000..288b232f00d --- /dev/null +++ b/src/ui/qgsowssourceselectbase.ui @@ -0,0 +1,502 @@ + + + QgsOWSSourceSelectBase + + + + 0 + 0 + 694 + 616 + + + + Add Layer(s) from a Server + + + + ../../../../.designer/backup../../../../.designer/backup + + + true + + + true + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Help + + + + + + + + 0 + 0 + + + + Ready + + + false + + + + + + + true + + + 1 + + + + Layers + + + + + + + + + false + + + C&onnect + + + + + + + &New + + + + + + + false + + + Edit + + + + + + + false + + + Delete + + + + + + + Qt::Horizontal + + + + 8 + 20 + + + + + + + + Load connections from file + + + Load + + + + + + + Save connections to file + + + Save + + + + + + + Adds a few example WMS servers + + + + + + Add default servers + + + + + + + + 0 + 0 + + + + QAbstractItemView::MultiSelection + + + true + + + + ID + + + + + Name + + + + + Title + + + + + Abstract + + + + + + + + + 0 + 0 + + + + + 16 + 64 + + + + Format + + + + + + + Options + + + + + + Layer name + + + mLayerNameLineEdit + + + + + + + + + + + + + Tile size + + + mTileWidthLineEdit + + + + + + + + + + Feature limit for GetFeatureInfo + + + mFeatureCountLineEdit + + + + + + + + + + + + + Coordinate Reference System + + + + + + Coordinate Reference System + + + mChangeCRSButton + + + + + + + false + + + Change ... + + + + + + + + + + + Layer Order + + + + + + Move selected layer UP + + + Up + + + + + + + Move selected layer DOWN + + + Down + + + + + + + Qt::Horizontal + + + + 391 + 30 + + + + + + + + 2 + + + + Layer + + + + + Style + + + + + + + + + Tilesets + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + false + + + + Layers + + + + + Styles + + + + + Size + + + + + Format + + + + + CRS + + + + + + + + + Server Search + + + + + + + + + Search + + + true + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + false + + + + Title + + + + + Description + + + + + URL + + + + + + + + Add selected row to WMS list + + + + + + + + + + + + mTabWidget + mConnectionsComboBox + mConnectButton + mNewButton + mEditButton + mDeleteButton + mAddDefaultButton + mLayersTreeWidget + mLayerNameLineEdit + mLayerUpButton + mLayerDownButton + mLayerOrderTreeWidget + mTilesetsTableWidget + mSearchTermLineEdit + mSearchButton + mSearchTableWidget + mSearchAddButton + mDialogButtonBox + + + + + mDialogButtonBox + rejected() + QgsOWSSourceSelectBase + reject() + + + 518 + 510 + + + 551 + 370 + + + + + From 7d500ea3519e6813649891a9d2654a169c186961 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 25 Apr 2012 18:35:18 +0200 Subject: [PATCH 02/19] initial WCS support based on GDAL --- src/providers/gdal/CMakeLists.txt | 17 +- src/providers/gdal/qgsgdaldataitems.cpp | 7 + src/providers/gdal/qgsgdalprovider.cpp | 31 +- src/providers/gdal/qgswcscapabilities.cpp | 704 ++++++++++++++++++++++ src/providers/gdal/qgswcscapabilities.h | 391 ++++++++++++ src/providers/gdal/qgswcssourceselect.cpp | 246 ++++++++ src/providers/gdal/qgswcssourceselect.h | 98 +++ 7 files changed, 1491 insertions(+), 3 deletions(-) create mode 100644 src/providers/gdal/qgswcscapabilities.cpp create mode 100644 src/providers/gdal/qgswcscapabilities.h create mode 100644 src/providers/gdal/qgswcssourceselect.cpp create mode 100644 src/providers/gdal/qgswcssourceselect.h diff --git a/src/providers/gdal/CMakeLists.txt b/src/providers/gdal/CMakeLists.txt index 2ef891e2c57..4ff2f6f43b0 100644 --- a/src/providers/gdal/CMakeLists.txt +++ b/src/providers/gdal/CMakeLists.txt @@ -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} @@ -14,6 +26,7 @@ ADD_LIBRARY (gdalprovider MODULE ${GDAL_SRCS} ${GDAL_MOC_SRCS}) TARGET_LINK_LIBRARIES (gdalprovider qgis_core + qgis_gui ) INSTALL(TARGETS gdalprovider diff --git a/src/providers/gdal/qgsgdaldataitems.cpp b/src/providers/gdal/qgsgdaldataitems.cpp index 146f80dbe43..d7ed36db458 100644 --- a/src/providers/gdal/qgsgdaldataitems.cpp +++ b/src/providers/gdal/qgsgdaldataitems.cpp @@ -1,6 +1,8 @@ #include "qgsgdaldataitems.h" #include "qgsgdalprovider.h" #include "qgslogger.h" +//#include "qgsowssourceselect.h" +#include "qgswcssourceselect.h" #include @@ -146,3 +148,8 @@ QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) } return 0; } + +QGISEXTERN QgsWCSSourceSelect * selectWidget( QWidget * parent, Qt::WFlags fl ) +{ + return new QgsWCSSourceSelect( parent, fl ); +} diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index 997a4270f5a..4d7cf102956 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -24,11 +24,13 @@ #include "qgsapplication.h" #include "qgscoordinatetransform.h" #include "qgsdataitem.h" +#include "qgsdatasourceuri.h" #include "qgsrectangle.h" #include "qgscoordinatereferencesystem.h" #include "qgsrasterbandstats.h" #include "qgsrasterlayer.h" #include "qgsrasterpyramid.h" +#include "qgswcscapabilities.h" #include #include @@ -105,8 +107,33 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) mGdalDataset = NULL; + // The uri is either a file name or encoded parameters for WCS + QString gdalUri = uri; + if ( uri.contains("url=") && uri.contains("identifier=") && !QFile::exists(uri) ) + { + // WCS + QgsDataSourceURI dsUri; + dsUri.setEncodedUri( uri ); + gdalUri = ""; + // prepareUri adds ? or & if necessary, GDAL fails otherwise + gdalUri += "" + QgsWcsCapabilities::prepareUri( dsUri.param("url") ) + ""; + gdalUri += "" + dsUri.param("identifier") + ""; + gdalUri += "" + dsUri.param("format") + ""; + + // TODO: There is no tag for CRS response. + // There is undocumented CRS tag, but it only overrides CRS param in requests + // but BBOX is left unchanged and thus results in server error (usually). + gdalUri += "&RESPONSE_CRS=" + dsUri.param("crs") + ""; + if ( dsUri.hasParam("username") && dsUri.hasParam("password") ) + { + gdalUri += "" + dsUri.param("username") + ":" + dsUri.param("password") + ""; + } + gdalUri += ""; + QgsDebugMsg( "WCS uri: " + gdalUri ); + } + //mGdalBaseDataset = GDALOpen( QFile::encodeName( uri ).constData(), GA_ReadOnly ); - mGdalBaseDataset = GDALOpen( TO8F( uri ), GA_ReadOnly ); + mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), GA_ReadOnly ); CPLErrorReset(); if ( mGdalBaseDataset == NULL ) @@ -1168,6 +1195,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] ); } diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp new file mode 100644 index 00000000000..c3b6e5133a2 --- /dev/null +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -0,0 +1,704 @@ +/*************************************************************************** + qgswcscapabilities.cpp - 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.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 + +#define WCS_THRESHOLD 200 // time to wait for an answer without emitting dataChanged() +#include "qgslogger.h" +#include "qgswcscapabilities.h" +#include "qgsowsconnection.h" + +#include + +#include "qgscoordinatetransform.h" +#include "qgsdatasourceuri.h" +#include "qgsrasterlayer.h" +#include "qgsrectangle.h" +#include "qgscoordinatereferencesystem.h" +#include "qgsnetworkaccessmanager.h" +#include +#include + +#include +#include +#include + +#if QT_VERSION >= 0x40500 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#define isfinite(x) _finite(x) +#endif + +#ifdef QGISDEBUG +#include +#include +#endif + +/* +QgsWcsCapabilities::QgsWcsCapabilities( QString const &theUri ) +{ + mUri.setEncodedUri( theUri ); + + QgsDebugMsg( "theUri = " + theUri ); +} +*/ + +QgsWcsCapabilities::QgsWcsCapabilities( QgsDataSourceURI const &theUri ): + mUri(theUri), + mCoverageCount(0) +{ + QgsDebugMsg( "uri = " + mUri.encodedUri() ); + + retrieveServerCapabilities(); +} + +QgsWcsCapabilities::QgsWcsCapabilities( ): + mCoverageCount(0) +{ +} + +QgsWcsCapabilities::~QgsWcsCapabilities() +{ + QgsDebugMsg( "deconstructing." ); +/* + if ( cacheReply ) + { + cacheReply->deleteLater(); + cacheReply = 0; + } +*/ +} + +void QgsWcsCapabilities::setUri( QgsDataSourceURI const &theUri ) +{ + mUri = theUri; + mCoverageCount = 0; + mCoveragesSupported.clear(); + QgsWcsCapabilitiesProperty c; + mCapabilities = c; + + retrieveServerCapabilities(true); +} + +QString QgsWcsCapabilities::prepareUri( QString uri ) +{ + if ( !uri.contains( "?" ) ) + { + uri.append( "?" ); + } + else if ( uri.right( 1 ) != "?" && uri.right( 1 ) != "&" ) + { + uri.append( "&" ); + } + + return uri; +} + +bool QgsWcsCapabilities::supportedCoverages( QVector &coverageSummary ) +{ + QgsDebugMsg( "Entering." ); + + // Allow the provider to collect the capabilities first. + if ( !retrieveServerCapabilities() ) + { + return false; + } + + coverageSummary = mCoveragesSupported; + + QgsDebugMsg( "Exiting." ); + + return true; +} + +/* +QString QgsWcsCapabilities::baseUrl() const +{ + return prepareUri( mUri.param("url") ); +} +*/ + +QString QgsWcsCapabilities::getCoverageUrl() const +{ + QString url = mCapabilities.operationsMetadata.getCoverage.dcp.http.get.xlinkHref; + // TODO: ignore getCoverage url + if ( url.isEmpty() ) + { + url = mUri.param("url"); + } + return url; +} + +bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) +{ + QgsDebugMsg( "entering." ); + + if ( mCapabilitiesResponse.isNull() || forceRefresh ) + { + // TODO: version + QString url = prepareUri( mUri.param("url") ) + "SERVICE=WCS&REQUEST=GetCapabilities"; + + mError = ""; + + QNetworkRequest request( url ); + setAuthorization( request ); + request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork ); + request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); + + QgsDebugMsg( QString( "getcapabilities: %1" ).arg( url ) ); + mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); + + connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) ); + connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ) ); + + while ( mCapabilitiesReply ) + { + QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); + } + + if ( mCapabilitiesResponse.isEmpty() ) + { + if ( mError.isEmpty() ) + { + mErrorFormat = "text/plain"; + mError = tr( "empty capabilities document" ); + } + return false; + } + + if ( mCapabilitiesResponse.startsWith( "" ) || + mCapabilitiesResponse.startsWith( "" ) ) + { + mErrorFormat = "text/html"; + mError = mCapabilitiesResponse; + return false; + } + + QgsDebugMsg( "Converting to Dom." ); + + bool domOK; + domOK = parseCapabilitiesDom( mCapabilitiesResponse, mCapabilities ); + + if ( !domOK ) + { + // We had an Dom exception - + // mErrorCaption and mError are pre-filled by parseCapabilitiesDom + + mError += tr( "\nTried URL: %1" ).arg( url ); + + QgsDebugMsg( "!domOK: " + mError ); + + return false; + } + + } + + QgsDebugMsg( "exiting." ); + + return true; +} + +void QgsWcsCapabilities::capabilitiesReplyFinished() +{ + if ( mCapabilitiesReply->error() == QNetworkReply::NoError ) + { + QVariant redirect = mCapabilitiesReply->attribute( QNetworkRequest::RedirectionTargetAttribute ); + if ( !redirect.isNull() ) + { + emit statusChanged( tr( "Capabilities request redirected." ) ); + + QNetworkRequest request( redirect.toUrl() ); + setAuthorization( request ); + request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork ); + request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); + + mCapabilitiesReply->deleteLater(); + QgsDebugMsg( QString( "redirected getcapabilities: %1" ).arg( redirect.toString() ) ); + mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); + + connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) ); + connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ) ); + return; + } + + mCapabilitiesResponse = mCapabilitiesReply->readAll(); + + if ( mCapabilitiesResponse.isEmpty() ) + { + mErrorFormat = "text/plain"; + mError = tr( "empty of capabilities: %1" ).arg( mCapabilitiesReply->errorString() ); + } + } + else + { + mErrorFormat = "text/plain"; + mError = tr( "Download of capabilities failed: %1" ).arg( mCapabilitiesReply->errorString() ); + QgsMessageLog::logMessage( mError, tr( "WCS" ) ); + mCapabilitiesResponse.clear(); + } + + mCapabilitiesReply->deleteLater(); + mCapabilitiesReply = 0; +} + +void QgsWcsCapabilities::capabilitiesReplyProgress( qint64 bytesReceived, qint64 bytesTotal ) +{ + QString msg = tr( "%1 of %2 bytes of capabilities downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QString( "unknown number of" ) : QString::number( bytesTotal ) ); + QgsDebugMsg( msg ); + emit statusChanged( msg ); +} + +QString QgsWcsCapabilities::stripNS ( const QString & name ) +{ + return name.contains( ":" ) ? name.section( ':', 1 ) : name; +} + +bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapabilitiesProperty &capabilities ) +{ + QgsDebugMsg( "entering." ); + +#ifdef QGISDEBUG + QFile file( QDir::tempPath() + "/qgis-wcs-capabilities.xml" ); + if ( file.open( QIODevice::WriteOnly ) ) + { + file.write( xml ); + file.close(); + } +#endif + + // Convert completed document into a Dom + QString errorMsg; + int errorLine; + int errorColumn; + bool contentSuccess = mCapabilitiesDom.setContent( xml, false, &errorMsg, &errorLine, &errorColumn ); + + if ( !contentSuccess ) + { + mErrorCaption = tr( "Dom Exception" ); + mErrorFormat = "text/plain"; + mError = tr( "Could not get WCS capabilities: %1 at line %2 column %3\nThis is probably due to an incorrect WMS Server URL.\nResponse was:\n\n%4" ) + .arg( errorMsg ) + .arg( errorLine ) + .arg( errorColumn ) + .arg( QString( xml ) ); + + QgsLogger::debug( "Dom Exception: " + mError ); + + return false; + } + + QDomElement docElem = mCapabilitiesDom.documentElement(); + + // Assert that the DTD is what we expected (i.e. a WCS Capabilities document) + QgsDebugMsg( "testing tagName " + docElem.tagName() ); + + if ( + docElem.tagName() != "Capabilities" + ) + { + mErrorCaption = tr( "Dom Exception" ); + mErrorFormat = "text/plain"; + mError = tr( "Could not get WCS capabilities in the expected format (DTD): no %1 found.\nThis might be due to an incorrect WMS Server URL.\nTag:%3\nResponse was:\n%4" ) + .arg( "Capabilities" ) + .arg( docElem.tagName() ) + .arg( QString( xml ) ); + + QgsLogger::debug( "Dom Exception: " + mError ); + + return false; + } + + capabilities.version = docElem.attribute( "version" ); + + // Start walking through XML. + QDomNode n = docElem.firstChild(); + + while ( !n.isNull() ) + { + QDomElement e = n.toElement(); // try to convert the node to an element. + if ( !e.isNull() ) + { + QString tagName = stripNS ( e.tagName() ); + if ( tagName == "ServiceIdentification" ) + { + QgsDebugMsg( " ServiceIdentification." ); + parseServiceIdentification( e, capabilities.serviceIdentification ); + } + else if ( tagName == "OperationsMetadata" ) + { + QgsDebugMsg( " OperationsMetadata." ); + parseOperationsMetadata( e, capabilities.operationsMetadata ); + } + else if ( tagName == "Contents" ) + { + QgsDebugMsg( " Contents." ); + parseCoverageSummary( e, capabilities.contents ); + } + } + n = n.nextSibling(); + } + + QgsDebugMsg( "exiting." ); + + return true; +} + + +void QgsWcsCapabilities::parseServiceIdentification( QDomElement const & e, QgsWcsServiceIdentification &serviceIdentification ) +{ + QgsDebugMsg( "entering." ); + + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + + if ( tagName == "Title" ) + { + serviceIdentification.title = el.text(); + } + else if ( tagName == "Abstract" ) + { + serviceIdentification.abstract = el.text(); + } + } + n1 = n1.nextSibling(); + } + + QgsDebugMsg( "exiting." ); +} + +void QgsWcsCapabilities::parseHttp( QDomElement const & e, QgsWcsHTTP& http ) +{ + QgsDebugMsg( "entering." ); + + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + if ( tagName == "Get" ) + { + QgsDebugMsg( " Get." ); + http.get.xlinkHref = el.attribute( "xlink:href" ); + } + } + n1 = n1.nextSibling(); + } + + QgsDebugMsg( "exiting." ); +} + +void QgsWcsCapabilities::parseDcp( QDomElement const & e, QgsWcsDCP& dcp ) +{ + QgsDebugMsg( "entering." ); + + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + if ( tagName == "HTTP" ) + { + QgsDebugMsg( " HTTP." ); + parseHttp( el, dcp.http ); + } + } + n1 = n1.nextSibling(); + } + + QgsDebugMsg( "exiting." ); +} + +void QgsWcsCapabilities::parseOperation( QDomElement const & e, QgsWcsOperation& operation ) +{ + QgsDebugMsg( "entering." ); + + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + + if ( tagName == "DCP" ) + { + QgsDebugMsg( " DCP." ); + parseDcp( el, operation.dcp ); + } + // TODO Parameter version + } + n1 = n1.nextSibling(); + } + + QgsDebugMsg( "exiting." ); +} + +void QgsWcsCapabilities::parseOperationsMetadata( QDomElement const & e, QgsWcsOperationsMetadata &operationsMetadata ) +{ + QgsDebugMsg( "entering." ); + + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + + if ( tagName == "GetCoverage" ) + { + QgsDebugMsg( " GetCoverage." ); + parseOperation( el, operationsMetadata.getCoverage ); + } + } + n1 = n1.nextSibling(); + } + + QgsDebugMsg( "exiting." ); +} + +void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCoverageSummary &coverageSummary, QgsWcsCoverageSummary *parent ) +{ + QgsDebugMsg("entering."); + + coverageSummary.orderId = ++mCoverageCount; + + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + QgsDebugMsg( tagName + " : " + el.text()); + + if ( tagName == "Identifier" ) + { + coverageSummary.identifier = el.text(); + QgsDebugMsg( "Identifier = " + el.text() ); + } + else if ( tagName == "Title" ) + { + coverageSummary.title = el.text(); + } + else if ( tagName == "Abstract" ) + { + coverageSummary.abstract = el.text(); + } + else if ( tagName == "SupportedFormat" ) + { + coverageSummary.supportedFormat << el.text(); + } + else if ( tagName == "SupportedCRS" ) + { + // TODO: SupportedCRS may be URL referencing a document + // URN format: urn:ogc:def:objectType:authority:version:code + // URN example: urn:ogc:def:crs:EPSG::4326 + QStringList urn = el.text().split(":"); + if ( urn.size() == 7 ) + { + coverageSummary.supportedCrs << urn.value(4) + ":" + urn.value(6); + } + } + else if ( tagName == "WGS84BoundingBox" ) + { + QDomElement wBoundLongitudeElem, eBoundLongitudeElem, sBoundLatitudeElem, nBoundLatitudeElem; + + QStringList lower = n1.namedItem( "ows:LowerCorner" ).toElement().text().split( QRegExp( " +" ) ); + QStringList upper = n1.namedItem( "ows:UpperCorner" ).toElement().text().split( QRegExp( " +" ) ); + + double w, e, s, n; + bool wOk, eOk, sOk, nOk; + w = lower.value(0).toDouble( &wOk ); + s = lower.value(1).toDouble( &sOk ); + e = upper.value(0).toDouble( &eOk ); + n = upper.value(1).toDouble( &nOk ); + if ( wOk && eOk && sOk && nOk ) + { + coverageSummary.wgs84BoundingBox = QgsRectangle( w, s, e, n ); + } + } + } + n1 = n1.nextSibling(); + } + + // We collected params to be inherited, do children + n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); // try to convert the node to an element. + if ( !el.isNull() ) + { + QString tagName = stripNS ( el.tagName() ); + + if ( tagName == "CoverageSummary" ) + { + QgsDebugMsg( " Nested coverage." ); + + QgsWcsCoverageSummary subCoverageSummary; + + // Inherit + subCoverageSummary.supportedCrs = coverageSummary.supportedCrs; + subCoverageSummary.supportedFormat = coverageSummary.supportedFormat; + + parseCoverageSummary( el, subCoverageSummary, &coverageSummary ); + + coverageSummary.coverageSummary.push_back( subCoverageSummary ); + } + } + n1 = n1.nextSibling(); + } + + if ( parent && parent->orderId > 1 ) // ignore Contents to put them on top level + { + QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2 has parent %3").arg(coverageSummary.orderId).arg(coverageSummary.identifier).arg(parent->orderId) ); + mCoverageParents[ coverageSummary.orderId ] = parent->orderId; + } + + if ( !coverageSummary.identifier.isEmpty() ) + { + QgsDebugMsg( "add coverage " + coverageSummary.identifier + " to supported" ); + mCoveragesSupported.push_back( coverageSummary ); + } + + if ( !coverageSummary.coverageSummary.empty() ) + { + mCoverageParentIdentifiers[ coverageSummary.orderId ] = QStringList() << coverageSummary.identifier << coverageSummary.title << coverageSummary.abstract; + } + QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2").arg(coverageSummary.orderId).arg(coverageSummary.identifier) ); + + QgsDebugMsg("exiting."); +} + +void QgsWcsCapabilities::coverageParents( QMap &parents, QMap &parentNames ) const +{ + parents = mCoverageParents; + parentNames = mCoverageParentIdentifiers; +} + +QString QgsWcsCapabilities::lastErrorTitle() +{ + return mErrorCaption; +} + +QString QgsWcsCapabilities::lastError() +{ + QgsDebugMsg( "returning '" + mError + "'." ); + return mError; +} + +QString QgsWcsCapabilities::lastErrorFormat() +{ + return mErrorFormat; +} + +void QgsWcsCapabilities::setAuthorization( QNetworkRequest &request ) const +{ + if ( mUri.hasParam("username") && mUri.hasParam("password") ) + { + request.setRawHeader( "Authorization", "Basic " + QString( "%1:%2" ).arg( mUri.param("username") ).arg( mUri.param("password") ).toAscii().toBase64() ); + } +} + +// TOD: GDAL supported formats? +/* +QVector QgsWcsCapabilities::supportedFormats() +{ + QVector formats; + QStringList mFormats, mLabels; + + + QList supportedFormats = QImageReader::supportedImageFormats(); + + if ( supportedFormats.contains( "png" ) ) + { + QgsWcsSupportedFormat p1 = { "image/png", "PNG" }; + QgsWcsSupportedFormat p2 = { "image/png; mode=24bit", "PNG24" }; // UMN mapserver + QgsWcsSupportedFormat p3 = { "image/png8", "PNG8" }; // used by geoserver + QgsWcsSupportedFormat p4 = { "png", "PNG" }; // used by french IGN geoportail + QgsWcsSupportedFormat p5 = { "pngt", "PNGT" }; // used by french IGN geoportail + + formats << p1 << p2 << p3 << p4 << p5; + } + + if ( supportedFormats.contains( "jpg" ) ) + { + QgsWcsSupportedFormat j1 = { "image/jpeg", "JPEG" }; + QgsWcsSupportedFormat j2 = { "jpeg", "JPEG" }; // used by french IGN geoportail + formats << j1 << j2; + } + + if ( supportedFormats.contains( "gif" ) ) + { + QgsWcsSupportedFormat g1 = { "image/gif", "GIF" }; + formats << g1; + } + + if ( supportedFormats.contains( "tiff" ) ) + { + QgsWcsSupportedFormat t1 = { "image/tiff", "TIFF" }; + formats << t1; + } + + return formats; +} +*/ + +void QgsWcsCapabilities::showMessageBox( const QString& title, const QString& text ) +{ + QgsMessageOutput *message = QgsMessageOutput::createMessageOutput(); + message->setTitle( title ); + message->setMessage( text, QgsMessageOutput::MessageText ); + message->showMessage(); +} + +QgsWcsCoverageSummary QgsWcsCapabilities::coverageSummary ( QString const & theIdentifier ) +{ + QgsDebugMsg ( "entered"); + foreach( QgsWcsCoverageSummary c, mCoveragesSupported ) + { + if ( c.identifier == theIdentifier ) return c; + } + QgsWcsCoverageSummary c; + return c; +} diff --git a/src/providers/gdal/qgswcscapabilities.h b/src/providers/gdal/qgswcscapabilities.h new file mode 100644 index 00000000000..ea1bc615418 --- /dev/null +++ b/src/providers/gdal/qgswcscapabilities.h @@ -0,0 +1,391 @@ +/*************************************************************************** + 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 +#include +#include +#include +#include +#include + +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 coverageSummary; +}; + +/** Contents structure */ +/* +struct QgsWcsContents +{ + QStringList supportedCrs; + QStringList supportedFormat; + QVector 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( QString const & theUri = 0 ); + + QgsWcsCapabilities( QgsDataSourceURI const & theUri ); + QgsWcsCapabilities( ); + + //! Destructor + ~QgsWcsCapabilities(); + + void setUri( QgsDataSourceURI const &theUri ); + + /** + * \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 &coverageSummary ); + + /** + * \brief Returns a map for the hierarchy of layers + */ + void coverageParents( QMap &parents, QMap &parentNames ) const; + + //! Get coverage summare for identifier + QgsWcsCoverageSummary coverageSummary ( QString const & theIdentifier ); + + /** + * Set the name of the connection for use in authentication where required + * \note added in 1.1 + */ + //void setConnectionName( QString const & connName ); + + /**Returns the base url + */ + //QString baseUrl() const; + + /** + * \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; + + //! set authorization header + void setAuthorization( QNetworkRequest &request ) const; + + //! get WCS Server version string + //QString wmsVersion(); + + //! get raster image encodings supported by the WCS Server, expressed as MIME types + //QStringList supportedImageEncodings(); + + /** + * \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(); + + //static QVector supportedFormats(); + + 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 ); + + /** + * \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 ); + + //! parse the WCS Service XML element + void parseServiceIdentification( QDomElement const &e, QgsWcsServiceIdentification &serviceIdentification ); + + //! parse the WCS Capability 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 ); + + //! parse the WCS Layer XML element + //void parseContents( QDomElement const &e, QgsWcsContents &contents ); + + /** + * \brief parse the full WCS ServiceExceptionReport XML document + * + * \note mErrorCaption and mError are updated to suit the results of this function. + */ + //bool parseServiceExceptionReportDom( QByteArray const &xml ); + + //! parse the WCS ServiceException XML element + //void parseServiceException( QDomElement const &e ); + + //! Data source URI of the WCS for this layer + //QString httpuri; + + //! Name of the stored connection + //QString connectionName; + + //! Data source uri + QgsDataSourceURI mUri; + + //! URL part of URI (httpuri) + //QString mBaseUrl; + + /** + * 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 + */ + QVector mCoveragesSupported; + + /** + * extents per layer (in WCS CRS:84 datum) + */ + //QMap extentForLayer; + + /** + * available CRSs per layer + */ + //QMap mCrsForLayer; + + /** + * available formats per layer + */ + //QMap mFormatForLayer; + + /** + * The reply to the capabilities request + */ + QNetworkReply *mCapabilitiesReply; + + /** + * The error caption associated with the last WCS error. + */ + QString mErrorCaption; + + /** + * The error message associated with the last WCS error. + */ + QString mError; + + /** The mime type of the message + */ + QString mErrorFormat; + + //! A QgsCoordinateTransform is used for transformation of WCS layer extents + //QgsCoordinateTransform *mCoordinateTransform; + + //! See if calculateExtents() needs to be called before extent() returns useful data + //bool extentDirty; + + int mCoverageCount; + + //! number of layers and parents + QMap mCoverageParents; + QMap mCoverageParentIdentifiers; + + //! Username for basic http authentication + QString mUserName; + + //! Password for basic http authentication + QString mPassword; + + //! whether to use hrefs from GetCapabilities (default) or + // the given base urls for GetMap and GetFeatureInfo + //bool mIgnoreGetCoverageUrl; + + +}; + + +#endif + +// ENDS diff --git a/src/providers/gdal/qgswcssourceselect.cpp b/src/providers/gdal/qgswcssourceselect.cpp new file mode 100644 index 00000000000..622617b7ac9 --- /dev/null +++ b/src/providers/gdal/qgswcssourceselect.cpp @@ -0,0 +1,246 @@ +/*************************************************************************** + 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 "qgswcssourceselect.h" +#include "qgswcscapabilities.h" +#include "qgsnumericsortlistviewitem.h" + +#include + +#define CPL_SUPRESS_CPLUSPLUS +#include + +#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() +{ +} + +bool QgsWCSSourceSelect::populateLayerList( ) +{ + QgsDebugMsg( "entered" ); +// mCRSs.clear(); + + // TODO: showError + + mCapabilities.setUri ( mUri ); + + QVector coverages; + if ( !mCapabilities.supportedCoverages( coverages ) ) + return false; + + QMap items; + QMap coverageParents; + QMap coverageParentNames; + mCapabilities.coverageParents( coverageParents, coverageParentNames ); + + mLayersTreeWidget->clear(); + mLayersTreeWidget->setSortingEnabled( true ); + + int coverageAndStyleCount = -1; + + for ( QVector::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 ) ); + } + + return true; +} + +void QgsWCSSourceSelect::addClicked( ) +{ + QgsDebugMsg ( "entered"); + QgsDataSourceURI uri = mUri; + + QList selectionList = mLayersTreeWidget->selectedItems(); + if ( selectionList.size() < 1 ) return; // should not happen + QString identifier = selectionList.value(0)->data( 0, Qt::UserRole + 0 ).toString(); + QgsDebugMsg ( " identifier = " + identifier ); + + uri.setParam( "identifier", identifier ); + + uri.setParam( "crs", selectedCrs() ); + + QgsDebugMsg ( "selectedFormat = " + selectedFormat() ); + uri.setParam( "format", selectedFormat() ); + + emit addRasterLayer( uri.encodedUri(), identifier, "gdal" ); +} + +void QgsWCSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged() +{ + QgsDebugMsg ( "entered"); + populateFormats(); + + populateCRS(); + + mAddButton->setEnabled(true); +} + +void QgsWCSSourceSelect::updateButtons() +{ + QgsDebugMsg ( "entered"); + //updateCRSWidgets(); + + if ( mLayersTreeWidget->selectedItems().isEmpty() ) + { + showStatusMessage( tr( "Select a layer" ) ); + } + else + { + if ( mCRS.isEmpty() ) + { + showStatusMessage( tr( "No CRS selected" ) ); + } + } + + mAddButton->setEnabled( !mLayersTreeWidget->selectedItems().isEmpty() && !mCRS.isEmpty() && !selectedFormat().isEmpty() ); +} + +QList QgsWCSSourceSelect::providerFormats() +{ + QgsDebugMsg ( "entered"); + QList formats; + 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; + + QgsOWSSupportedFormat format = { mimeType, desc }; + + QgsDebugMsg ( "add GDAL format " + mimeType + " " + desc ); + + if ( mimeType == "image/tiff" ) + { + formats.prepend ( format ); + } + else + { + formats.append ( format ); + } + } + + return formats; +} + +QStringList QgsWCSSourceSelect::serverFormats() +{ + QgsDebugMsg ( "entered"); + + QList selectionList = mLayersTreeWidget->selectedItems(); + if ( selectionList.size() < 1 ) return QStringList(); + QString identifier = selectionList.value(0)->data( 0, Qt::UserRole + 0 ).toString(); + QgsDebugMsg ( " identifier = " + identifier ); + + QgsWcsCoverageSummary c = mCapabilities.coverageSummary(identifier); + return c.supportedFormat; +} + +QStringList QgsWCSSourceSelect::serverCRS() +{ + QgsDebugMsg ( "entered"); + + QList selectionList = mLayersTreeWidget->selectedItems(); + if ( selectionList.size() < 1 ) return QStringList(); + QString identifier = selectionList.value(0)->data( 0, Qt::UserRole + 0 ).toString(); + QgsDebugMsg ( " identifier = " + identifier ); + + QgsWcsCoverageSummary c = mCapabilities.coverageSummary(identifier); + + return c.supportedCrs; +} + +QStringList QgsWCSSourceSelect::layerCRS( int id ) +{ + QVector coverages; + if ( !mCapabilities.supportedCoverages( coverages ) ) + foreach ( QgsWcsCoverageSummary c, coverages ) + { + if ( c.orderId == id ) + { + return c.supportedCrs; + } + } + return QStringList(); +} + +void QgsWCSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item ) +{ + // TODO: I am not convinced to disable layers according to selected CRS +} diff --git a/src/providers/gdal/qgswcssourceselect.h b/src/providers/gdal/qgswcssourceselect.h new file mode 100644 index 00000000000..4dc06950d33 --- /dev/null +++ b/src/providers/gdal/qgswcssourceselect.h @@ -0,0 +1,98 @@ +/*************************************************************************** + 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 , 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 +#include + +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; + + /** + * \brief Populate the layer list - private for now. + * + * \retval false if the layers could not be retrieved or parsed - + * see mWmsProvider->errorString() for more info + */ + bool populateLayerList( ); + + //! Add layer + void addClicked(); + + //! Signaled when a layer selection is changed. + void on_mLayersTreeWidget_itemSelectionChanged(); + + void enableLayersForCrs( QTreeWidgetItem *item ); + + void updateButtons(); + + QList providerFormats(); + + QStringList serverFormats(); + + QStringList serverCRS(); + + QStringList layerCRS( int id ); + +}; +#endif // QGSWCSSOURCESELECT_H + + From 7ddadbfec557861d851db31852023706bdd6d3aa Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 25 Apr 2012 18:36:44 +0200 Subject: [PATCH 03/19] WCS support --- images/images.qrc | 1 + images/themes/default/mActionAddWcsLayer.png | Bin 0 -> 2060 bytes src/app/qgisapp.cpp | 23 +++++++++++++++++++ src/app/qgisapp.h | 3 +++ src/core/CMakeLists.txt | 2 ++ src/gui/CMakeLists.txt | 4 ++++ src/ui/qgisapp.ui | 13 ++++++++++- 7 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 images/themes/default/mActionAddWcsLayer.png diff --git a/images/images.qrc b/images/images.qrc index 871a75769d0..603b0c4a8cf 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -33,6 +33,7 @@ themes/default/mActionAddRing.png themes/default/mActionAddSpatiaLiteLayer.png themes/default/mActionAddVertex.png + themes/default/mActionAddWcsLayer.png themes/default/mActionAddWmsLayer.png themes/default/mActionAlignBottom.png themes/default/mActionAlignHCenter.png diff --git a/images/themes/default/mActionAddWcsLayer.png b/images/themes/default/mActionAddWcsLayer.png new file mode 100644 index 0000000000000000000000000000000000000000..20d8ada93e78b80d6cfa02d3474af482303858c1 GIT binary patch literal 2060 zcmV+n2=n)eP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00VXa00VXbebs`@00007bV*G`2iyb` z3jij-TtZm@00)doL_t(o!^M|rjGa{($A9OXce(GqckVK`vv16FoNjbVJ7u~Eg<3k+ zA|eE%6VX!R5<@V4P-{@5_`&!^OfzbFD-~4F)%P|Gg>DWB(Wo(^8ZCX?tcN@1k^N&<7q1i^rpDLaZvZOL;7lZLY_7NZ zB_Rid1;Wx`_-N(hNsmm)BmZQX{HfetFXyeks;s zBti}Nx`ykO30NRjNc@wcy)s!D0}j3)iL)fu+wiGCw~3_%Xo;>0zIw|xwh!-M`zLm= zY5twyON5q$rNkMwu^Q}0fZ%%uV8qNvqc_wGQwX#tz!#te`2TUq2Rw=JCCXPs6N>Pv zumybcJp-^~&h^3(2>qsE4Z?q08u>H8gf9`kz|;z(*FZe$7=xd5<&fjS{!P2UIE zx_-+{3Jd6M>V50ZJ^jPnI)4KQjTZ3W3tu7KIDrZp3%zV@ZUDM^h8u@AuH4++-LlE8 z6#5@|{(DkrNQ4p$^bEY?n~qo~9kI@Tdrdl+A&DVXojY3(boC6^uU)(3*B{w5xN*b! z6@Vs_E%KA!d>h}Jas8~t6L@Kful?y+g`jKUmZ8smcIc^<1AVa%^t2$Pz}HYJyI2@d zgTEbmfg|USB9sQH*>>kP273nq_~na_@!au0AWgu6iQ*(oNvgT(Ywrr+%suzZtru$F z|JbKDK6v+CHwz^tXD>`(By$`;IYwvOJbGIfGFBcZZRE+8@(8673W}BDTMCnfBxlFZ zA}o!vp=@btCu?~5+HbE~1!wNL-`rJ_U;0dU?7?<7El!V&Q1d*xIvZ(fiZj2b4a2hd z>5qO!_ShtTZ6@3G+e;AMtPX*$Lahq!MM3&dG70?rs-5t@g{zjw4Dr-;qGBpJPC;HF z-mw5-I7lf81uY^*hJ1RGb7!iIrcWV*CIXNG9NXby>LN!*kFfvDKE~6R(Fn>lP44-; z&Yn%*3|ziy2p$W!eff^k1sD$x(MKgi(-eNY?1Rsew#m0^PNlo<(aBQt|YQBlZur ztSirIzGRBoWhdR!yp%ajVBQ)QUv43ku~~7Vi^={XX&X$Zg@A%eC54r6NiQ!@ch1I| zG-*z00_|le>_wOR5aAZ=ptEGwd)z;gQ-K$!&Y^^)*j7a=je(-B;Lve6Mn_c=^Cw7_ zG{@`@VRYRFi4fVP6_Sf9XaROs;$>6#rAaiJyhn7_6E>JwaG0;9xu^LZFCP+Yn*hnfbbM$JPy6Gi&94bWryCFwFgd? zJD>HN@5gVx7iC5$Cp787Jf89afss+@B21U3nIEZOnik>q6-1YBp?>fSh|ZNz=V2;M zy|ZISp)E##NngGxSLL_W_RcgCd544`Wn;yWqjdL)gHT&7kGN?0OJz}F?9*s zGI64f1e+Jow)&F<`!*w_q(vs_h(JXef1h;-jyVMx{~&~>#92sPW@?4WFjNX z2a>MVwq>%se=TpwPNeXt%qvlxSHY5s<%vbauiMO}lEzXJTS;ssNLGA`(xTS1j8b9| zyQjP#9{v2X?3@7n_3oa%-+e9f<6W04bT!m7X0?M5lv*s7IUQ_jSx;i%JA|70hy+Yb zC9#yC>_gJkL>!A?z(QKq$w=6FXij_PzYb}PZ#{9oa{H02v7ps(P!%7`tZ*uH3!~jb zMB|Ml0w(c*!jLn_eGQJOFl$f|+B;q5-e=Y|c-O?|4u7<%tl{P9st(1Q1e!jH^kznxdyE`faLm^NyXQgLQwKFuS~i7k7lZOKE9^@(zS5Bccf-7KRztJo_J_Y zNjhJQ2Lh|sHQRk%Ath}o2%7?13cup%DuUyiTLT+~5YyMnZfC^}`*&Um#VxrCbo5ti q>xVi+>IT3B_5t4zLgcO$z&`<}qx|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" ) ); @@ -2632,6 +2634,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( 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 ) diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 6da87467a6a..e8bac6f4445 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -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; } @@ -763,6 +764,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 diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 76f4920b5bc..096ecc05f79 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -76,6 +76,7 @@ SET(QGIS_CORE_SRCS qgsmessagelog.cpp qgscredentials.cpp qgsoverlayobject.cpp + qgsowsconnection.cpp qgspalgeometry.cpp qgspallabeling.cpp qgspalobjectpositionmanager.cpp @@ -326,6 +327,7 @@ SET(QGIS_CORE_HDRS qgsmimedatautils.h qgscredentials.h qgsoverlayobjectpositionmanager.h + qgsowsconnection.h qgspallabeling.h qgspalobjectpositionmanager.h qgspluginlayer.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 22a6b0e341f..b39ebb8c9ec 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -65,6 +65,7 @@ qgsnewhttpconnection.cpp qgsnewvectorlayerdialog.cpp qgsnumericsortlistviewitem.cpp qgscredentialdialog.cpp +qgsowssourceselect.cpp qgsprojectbadlayerguihandler.cpp qgsprojectionselector.cpp qgsquickprint.cpp @@ -137,6 +138,7 @@ qgsmessagelogviewer.h qgsnewhttpconnection.h qgsnewvectorlayerdialog.h qgscredentialdialog.h +qgsowssourceselect.h qgsprojectionselector.h qgsquickprint.h qgsludialog.h @@ -172,6 +174,7 @@ qgsmaptoolpan.h qgsmaptoolzoom.h qgsmessageviewer.h qgscredentialdialog.h +qgsowssourceselect.h qgsprojectionselector.h qgsrubberband.h qgsvertexmarker.h @@ -204,6 +207,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 diff --git a/src/ui/qgisapp.ui b/src/ui/qgisapp.ui index 3ff2a01140c..68c0c56418a 100644 --- a/src/ui/qgisapp.ui +++ b/src/ui/qgisapp.ui @@ -17,7 +17,7 @@ 0 0 1052 - 21 + 27 @@ -150,6 +150,7 @@ + @@ -253,6 +254,7 @@ + @@ -1648,6 +1650,15 @@ Offset Curve + + + + :/images/themes/default/mActionAddWcsLayer.png:/images/themes/default/mActionAddWcsLayer.png + + + Add WCS Layer... + + From f7babebf3b73ae039d41d7a0fafa9ad9ee903af7 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Thu, 26 Apr 2012 10:41:18 +0200 Subject: [PATCH 04/19] check if provider is valid --- src/core/raster/qgsrasterlayer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index bd0a4481084..8f0f36a5b01 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -2224,6 +2224,10 @@ void QgsRasterLayer::setDataProvider( QString const & provider ) { return; } + if ( !mDataProvider->isValid() ) + { + return; + } setNoDataValue( mDataProvider->noDataValue() ); From 58c377497f4e42bcc5e401fda195c47b1376e158 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Thu, 26 Apr 2012 11:00:17 +0200 Subject: [PATCH 05/19] better hide unused widgets --- src/gui/qgsnewhttpconnection.cpp | 17 +++++++++++------ src/ui/qgsnewhttpconnectionbase.ui | 6 +++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/gui/qgsnewhttpconnection.cpp b/src/gui/qgsnewhttpconnection.cpp index e73fce880e9..0389ca58b9f 100644 --- a/src/gui/qgsnewhttpconnection.cpp +++ b/src/gui/qgsnewhttpconnection.cpp @@ -53,15 +53,20 @@ QgsNewHttpConnection::QgsNewHttpConnection( cbxIgnoreGetMapURI->setChecked( settings.value( key + "/ignoreGetMapURI", false ).toBool() ); cbxIgnoreGetFeatureInfoURI->setChecked( settings.value( key + "/ignoreGetFeatureInfoURI", false ).toBool() ); } - else - { - cbxIgnoreGetMapURI->setVisible( false ); - cbxIgnoreGetFeatureInfoURI->setVisible( false ); - } - 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 ); } diff --git a/src/ui/qgsnewhttpconnectionbase.ui b/src/ui/qgsnewhttpconnectionbase.ui index 3dd4ca7f57c..4ba8292070a 100644 --- a/src/ui/qgsnewhttpconnectionbase.ui +++ b/src/ui/qgsnewhttpconnectionbase.ui @@ -6,8 +6,8 @@ 0 0 - 507 - 322 + 500 + 311 @@ -28,7 +28,7 @@ - + Connection details From 866fa9c84a295c3cebadcbedc141ed780bbce7f0 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Thu, 26 Apr 2012 11:01:56 +0200 Subject: [PATCH 06/19] WCS better version support --- src/gui/qgsowssourceselect.cpp | 339 ++-------------------- src/gui/qgsowssourceselect.h | 54 ++-- src/providers/gdal/qgsgdalprovider.cpp | 6 +- src/providers/gdal/qgswcscapabilities.cpp | 39 ++- src/providers/gdal/qgswcscapabilities.h | 5 +- src/providers/gdal/qgswcssourceselect.cpp | 40 +-- src/providers/gdal/qgswcssourceselect.h | 25 +- src/ui/qgsowssourceselectbase.ui | 4 +- 8 files changed, 118 insertions(+), 394 deletions(-) diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp index c12df80786c..ee114fff94d 100644 --- a/src/gui/qgsowssourceselect.cpp +++ b/src/gui/qgsowssourceselect.cpp @@ -90,12 +90,9 @@ QgsOWSSourceSelect::QgsOWSSourceSelect( QString service, QWidget * parent, Qt::W QgsCoordinateReferenceSystem currentRefSys( currentCRS, QgsCoordinateReferenceSystem::InternalCrsId ); if ( currentRefSys.isValid() ) { - mCRS = currentRefSys.authid(); + mSelectedCRS = currentRefSys.authid(); } } - - // set up the default WMS Coordinate Reference System - //mCRSLabel->setText( descriptionForAuthId( mCRS ) ); } else { @@ -143,33 +140,24 @@ void QgsOWSSourceSelect::populateFormats() layout->addWidget( btn ); } - // default to first encoding - /* - if ( mImageFormatGroup->buttons().size() > 0 ) - { - mImageFormatGroup->button( 0 )->setChecked( true ); - } - */ - //mImageFormatsGroupBox->setDisabled( true ); - layout->addStretch(); mImageFormatsGroupBox->setLayout( layout ); } - // Show supported by server only + // Show supported by server only foreach( QAbstractButton *b, mImageFormatGroup->buttons() ) { b->setHidden( true ); } int firstVisible = -1; - foreach( QString encoding, serverFormats() ) + foreach( QString format, selectedLayersFormats() ) { - QgsDebugMsg( "server format = " + encoding ); - int id = mMimeMap.value( encoding, -1 ); + QgsDebugMsg( "server format = " + format ); + int id = mMimeMap.value( format, -1 ); if ( id < 0 ) { - QgsDebugMsg( QString( "encoding %1 not supported." ).arg( encoding ) ); + QgsDebugMsg( QString( "format %1 not supported." ).arg( format ) ); continue; } @@ -177,7 +165,7 @@ void QgsOWSSourceSelect::populateFormats() if ( firstVisible == -1 ) firstVisible = id; } // Set first if no one visible is checked - if ( !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() && firstVisible > -1 ) + if ( mImageFormatGroup->checkedId() < 0 || ( !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() && firstVisible > -1 ) ) { mImageFormatGroup->button( firstVisible )->setChecked(true); } @@ -302,9 +290,8 @@ QgsNumericSortTreeWidgetItem *QgsOWSSourceSelect::createItem( return item; } -bool QgsOWSSourceSelect::populateLayerList( ) +void QgsOWSSourceSelect::populateLayerList( ) { - return true; } void QgsOWSSourceSelect::on_mConnectButton_clicked() @@ -320,10 +307,7 @@ void QgsOWSSourceSelect::on_mConnectButton_clicked() QApplication::setOverrideCursor( Qt::WaitCursor ); QgsDebugMsg( "call populateLayerList" ); - if ( !populateLayerList() ) - { - //showError( theProvider ); - } + populateLayerList(); QApplication::restoreOverrideCursor(); } @@ -331,88 +315,10 @@ void QgsOWSSourceSelect::on_mConnectButton_clicked() void QgsOWSSourceSelect::addClicked() { QgsDebugMsg( "entered"); -/* - QStringList layers; - QStringList styles; - QString format; - QString crs; - - QgsDataSourceURI uri = mUri; - - if ( mTilesetsTableWidget->selectedItems().isEmpty() ) - { - collectSelectedLayers( layers, styles ); - crs = mCRS; - //format = mProviderFormats[ mImageFormatGroup->checkedId()].format; - - if ( mTileWidthLineEdit->text().toInt() > 0 && mTileHeightLineEdit->text().toInt() > 0 ) - { - uri.setParam( "tileWidth", mTileWidthLineEdit->text() ); - uri.setParam( "tileHeight", mTileHeightLineEdit->text() ); - } - } - else - { - QTableWidgetItem *item = mTilesetsTableWidget->selectedItems().first(); - layers = item->data( Qt::UserRole + 0 ).toStringList(); - styles = item->data( Qt::UserRole + 1 ).toStringList(); - format = item->data( Qt::UserRole + 2 ).toString(); - crs = item->data( Qt::UserRole + 3 ).toString(); - - uri.setParam( "tileWidth", item->data( Qt::UserRole + 4 ).toString() ); - uri.setParam( "tileHeight", item->data( Qt::UserRole + 5 ).toString() ); - uri.setParam( "tileResolutions", item->data( Qt::UserRole + 6 ).toStringList() ); - } - uri.setParam( "layers", layers ); - uri.setParam( "styles", styles ); - //uri.setParam( "format", format ); - uri.setParam( "crs", crs ); - - if ( mFeatureCountLineEdit->text().toInt() > 0 ) - { - uri.setParam( "featureCount", mFeatureCountLineEdit->text() ); - } - - QgsDebugMsg( "crs = " + crs ); - - QgsDebugMsg( "uri = " + uri.encodedUri() ); - - // TODO - QString providerKey = "gdal"; - emit addRasterLayer( uri.encodedUri(), - mLayerNameLineEdit->text().isEmpty() ? layers.join( "/" ) : mLayerNameLineEdit->text(), - providerKey ); -*/ } void QgsOWSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item ) { -/* - QString layerName = item->data( 0, Qt::UserRole + 0 ).toString(); - QString styleName = item->data( 0, Qt::UserRole + 1 ).toString(); - - if ( !layerName.isEmpty() && styleName.isEmpty() ) - { - // layer - bool disable = !item->data( 0, Qt::UserRole + 2 ).toStringList().contains( mCRS, Qt::CaseInsensitive ); - - item->setDisabled( disable ); - - // propagate to styles - for ( int i = 0; i < item->childCount(); i++ ) - { - item->child( i )->setDisabled( disable ); - } - } - else - { - // recurse to child layers - for ( int i = 0; i < item->childCount(); i++ ) - { - enableLayersForCrs( item->child( i ) ); - } - } -*/ } void QgsOWSSourceSelect::on_mChangeCRSButton_clicked() @@ -427,7 +333,7 @@ void QgsOWSSourceSelect::on_mChangeCRSButton_clicked() QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector( this ); mySelector->setMessage(); - mySelector->setOgcWmsCrsFilter( mCRSs ); + mySelector->setOgcWmsCrsFilter( mSelectedLayersCRSs ); QString myDefaultCrs = QgsProject::instance()->readEntry( "SpatialRefSys", "/ProjectCrs", GEO_EPSG_CRS_AUTHID ); QgsCoordinateReferenceSystem defaultCRS; @@ -439,218 +345,43 @@ void QgsOWSSourceSelect::on_mChangeCRSButton_clicked() if ( !mySelector->exec() ) return; - mCRS = mySelector->selectedAuthId(); + mSelectedCRS = mySelector->selectedAuthId(); delete mySelector; - mCRSLabel->setText( descriptionForAuthId( mCRS ) ); + mSelectedCRSLabel->setText( descriptionForAuthId( mSelectedCRS ) ); for ( int i = 0; i < mLayersTreeWidget->topLevelItemCount(); i++ ) { enableLayersForCrs( mLayersTreeWidget->topLevelItem( i ) ); } - // TODO - //updateButtons(); - - // update the display of this widget - update(); + updateButtons(); } -void QgsOWSSourceSelect::applySelectionConstraints( QTreeWidgetItem *item ) -{ - if ( item->childCount() == 0 ) - { - return; - } - - int styles = 0; - for ( int i = 0; i < item->childCount(); i++ ) - { - QTreeWidgetItem *child = item->child( i ); - QString style = child->data( 0, Qt::UserRole + 1 ).toString(); - if ( !style.isEmpty() ) - styles++; - } - - if ( styles > 0 ) - { - if ( styles < item->childCount() ) - { - return; - } - - QTreeWidgetItem *style = 0; - QTreeWidgetItem *firstNewStyle = 0; - for ( int i = 0; i < item->childCount(); i++ ) - { - QTreeWidgetItem *child = item->child( i ); - if ( child->isSelected() ) - { - if ( !firstNewStyle && !mCurrentSelection.contains( child ) ) - firstNewStyle = child; - - if ( !style ) - style = child; - - child->setSelected( false ); - } - } - - if ( firstNewStyle || style ) - { - // individual style selected => unselect layer and all parent groups - QTreeWidgetItem *parent = item; - while ( parent ) - { - parent->setSelected( false ); - parent = parent->parent(); - } - - if ( firstNewStyle ) - firstNewStyle->setSelected( true ); - else if ( style ) - style->setSelected( true ); - } - } - else - { - // no styles => layer or layer group => - // process child layers and style selection first - // then - // if some child layers are selected, deselect the group and all parents - // otherwise keep the selection state of the group - int n = 0; - for ( int i = 0; i < item->childCount(); i++ ) - { - QTreeWidgetItem *child = item->child( i ); - applySelectionConstraints( child ); - if ( child->isSelected() ) - n++; - } - - if ( n > 0 ) - { - if ( item->isSelected() ) - { - for ( int i = 0; i < n; i++ ) - { - QTreeWidgetItem *child = item->child( i ); - child->setSelected( false ); - } - item->setExpanded( false ); - } - else - { - for ( QTreeWidgetItem *parent = item->parent(); parent; parent = parent->parent() ) - { - parent->setSelected( false ); - } - } - } - } -} - -void QgsOWSSourceSelect::collectNamedLayers( QTreeWidgetItem *item, QStringList &layers, QStringList &styles ) -{ - QString layerName = item->data( 0, Qt::UserRole + 0 ).toString(); - QString styleName = item->data( 0, Qt::UserRole + 1 ).toString(); - if ( layerName.isEmpty() ) - { - // layer group - for ( int i = 0; i < item->childCount(); i++ ) - collectNamedLayers( item->child( i ), layers, styles ); - } - else if ( styleName.isEmpty() ) - { - // named layers - layers << layerName; - styles << ""; - - if ( mCRSs.isEmpty() ) - mCRSs = item->data( 0, Qt::UserRole + 2 ).toStringList().toSet(); - else - mCRSs.intersect( item->data( 0, Qt::UserRole + 2 ).toStringList().toSet() ); - } -} - -/** - * retrieve selected layers - */ void QgsOWSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged() { - QgsDebugMsg ( "entered"); - mLayersTreeWidget->blockSignals( true ); - for ( int i = 0; i < mLayersTreeWidget->topLevelItemCount(); i++ ) - { - applySelectionConstraints( mLayersTreeWidget->topLevelItem( i ) ); - } - mCurrentSelection = mLayersTreeWidget->selectedItems(); - mLayersTreeWidget->blockSignals( false ); - - - // selected layers with styles - QStringList layers; - QStringList styles; - - mCRSs.clear(); - - // determine selected layers and styles and set of crses that are available for all layers - foreach( QTreeWidgetItem *item, mLayersTreeWidget->selectedItems() ) - { - QString layerName = item->data( 0, Qt::UserRole + 0 ).toString(); - QString styleName = item->data( 0, Qt::UserRole + 1 ).toString(); - - if ( layerName.isEmpty() ) - { - // layers groups: collect named layers of group and add using the default style - collectNamedLayers( item, layers, styles ); - } - else if ( styleName.isEmpty() ) - { - // named layer: add using default style - layers << layerName; - styles << ""; - if ( mCRSs.isEmpty() ) - mCRSs = item->data( 0, Qt::UserRole + 2 ).toStringList().toSet(); - else - mCRSs.intersect( item->data( 0, Qt::UserRole + 2 ).toStringList().toSet() ); - } - else - { - // style: add named layer with selected style - layers << layerName; - styles << styleName; - if ( mCRSs.isEmpty() ) - mCRSs = item->parent()->data( 0, Qt::UserRole + 2 ).toStringList().toSet(); - else - mCRSs.intersect( item->parent()->data( 0, Qt::UserRole + 2 ).toStringList().toSet() ); - } - } - - updateButtons(); } void QgsOWSSourceSelect::populateCRS() { - mCRSs = serverCRS().toSet(); - //mCRSGroupBox->setTitle( tr( "Options (%n coordinate reference systems available)", "crs count", mCRSs.count() ) ); - mCRSGroupBox->setTitle( tr( "Coordinate Reference System (%n available)", "crs count", mCRSs.count() ) ); + mSelectedLayersCRSs = selectedLayersCRSs().toSet(); + mCRSGroupBox->setTitle( tr( "Coordinate Reference System (%n available)", "crs count", mSelectedLayersCRSs.count() ) ); - mChangeCRSButton->setDisabled( mCRSs.isEmpty() ); + mChangeCRSButton->setDisabled( mSelectedLayersCRSs.isEmpty() ); - if ( !mCRSs.isEmpty() ) + if ( !mSelectedLayersCRSs.isEmpty() ) { // check whether current CRS is supported // if not, use one of the available CRS QString defaultCRS; - QSet::const_iterator it = mCRSs.begin(); - for ( ; it != mCRSs.end(); it++ ) + QSet::const_iterator it = mSelectedLayersCRSs.begin(); + for ( ; it != mSelectedLayersCRSs.end(); it++ ) { - if ( it->compare( mCRS, Qt::CaseInsensitive ) == 0 ) + if ( it->compare( mSelectedCRS, Qt::CaseInsensitive ) == 0 ) break; // save first CRS in case the current CRS is not available - if ( it == mCRSs.begin() ) + if ( it == mSelectedLayersCRSs.begin() ) defaultCRS = *it; // prefer value of DEFAULT_GEO_EPSG_CRS_ID if available @@ -658,20 +389,20 @@ void QgsOWSSourceSelect::populateCRS() defaultCRS = *it; } - if ( it == mCRSs.end() ) + if ( it == mSelectedLayersCRSs.end() ) { // not found - mCRS = defaultCRS; - mCRSLabel->setText( descriptionForAuthId( mCRS ) ); + mSelectedCRS = defaultCRS; + mSelectedCRSLabel->setText( descriptionForAuthId( mSelectedCRS ) ); } } else { - mCRS = ""; - mCRSLabel->setText( "" ); + mSelectedCRS = ""; + mSelectedCRSLabel->setText( "" ); } - mChangeCRSButton->setEnabled( !mCRSs.isEmpty() ); + mChangeCRSButton->setEnabled( !mSelectedLayersCRSs.isEmpty() ); } void QgsOWSSourceSelect::on_mTilesetsTableWidget_itemClicked( QTableWidgetItem *item ) @@ -720,15 +451,15 @@ QString QgsOWSSourceSelect::selectedFormat() } else { - // TODO: do encoding in subclass (WMS) + // TODO: do format in subclass (WMS) //return QUrl::toPercentEncoding( mProviderFormats[ id ].format ); return mProviderFormats[ id ].format; } } -QString QgsOWSSourceSelect::selectedCrs() +QString QgsOWSSourceSelect::selectedCRS() { - return mCRS; + return mSelectedCRS; } void QgsOWSSourceSelect::setConnectionListPosition() @@ -991,22 +722,16 @@ QList QgsOWSSourceSelect::providerFormats() return QList(); } -QStringList QgsOWSSourceSelect::serverFormats() +QStringList QgsOWSSourceSelect::selectedLayersFormats() { return QStringList(); } -QStringList QgsOWSSourceSelect::serverCRS() +QStringList QgsOWSSourceSelect::selectedLayersCRSs() { return QStringList(); } -QStringList QgsOWSSourceSelect::layerCRS( int id ) -{ - Q_UNUSED ( id ); - return QStringList(); -} - void QgsOWSSourceSelect::updateButtons() { } diff --git a/src/gui/qgsowssourceselect.h b/src/gui/qgsowssourceselect.h index 49e13db5e11..0e6b300a98a 100644 --- a/src/gui/qgsowssourceselect.h +++ b/src/gui/qgsowssourceselect.h @@ -105,6 +105,12 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase 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 @@ -113,12 +119,12 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase virtual QList providerFormats(); //! List of formats supported for currently selected layer item(s) - virtual QStringList serverFormats(); + virtual QStringList selectedLayersFormats(); //! Server CRS supported for currently selected layer item(s) - virtual QStringList serverCRS(); + virtual QStringList selectedLayersCRSs(); - virtual QStringList layerCRS( int id ); + //virtual QStringList layerCRS( int id ); //! Populate the connection list combo box void populateConnectionList(); @@ -150,25 +156,13 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase //! Embedded mode, without 'Close' bool mEmbeddedMode; - //! Selected CRS - QString mCRS; - - //! Common CRSs for selected layers - QSet mCRSs; - - //! Supported formats - QList mProviderFormats; - - //! Map mime types to supported formats - QMap mMimeMap; /** - * \brief Populate the layer list - private for now. + * \brief Populate the layer list. * - * \retval false if the layers could not be retrieved or parsed - - * see mWmsProvider->errorString() for more info + * \retval false if the layers could not be retrieved or parsed */ - virtual bool populateLayerList( ); + virtual void populateLayerList( ); //! create an item including possible parents QgsNumericSortTreeWidgetItem *createItem( int id, @@ -194,26 +188,17 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase void addWMSListRow( const QDomElement& item, int row ); void addWMSListItem( const QDomElement& el, int row, int column ); - void applySelectionConstraints( QTreeWidgetItem *item ); - void collectNamedLayers( QTreeWidgetItem *item, QStringList &layers, QStringList &styles ); virtual void enableLayersForCrs( QTreeWidgetItem *item ); //! Returns currently selected format QString selectedFormat(); //! Returns currently selected Crs - QString selectedCrs(); + QString selectedCRS(); QList mCurrentSelection; QTableWidgetItem* mCurrentTileset; - signals: - void addRasterLayer( QString const & rasterLayerPath, - QString const & baseName, - QString const & providerKey ); - void connectionsChanged(); - - protected: //! Name for selected connection QString mConnName; @@ -223,6 +208,19 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase //! URI for selected connection QgsDataSourceURI mUri; + private: + //! Selected CRS + QString mSelectedCRS; + + //! Common CRSs for selected layers + QSet mSelectedLayersCRSs; + + //! Supported formats + QList mProviderFormats; + + //! Map mime types to supported formats + QMap mMimeMap; + private slots: void on_mSearchButton_clicked(); void on_mAddWMSButton_clicked(); diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index 4d7cf102956..61212833c47 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "gdalwarper.h" #include "ogr_spatialref.h" @@ -112,11 +113,13 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) if ( uri.contains("url=") && uri.contains("identifier=") && !QFile::exists(uri) ) { // WCS + // GDAL currently (4/2012) supports WCS 1.0.0 (default) and 1.1.0 + // QgsDataSourceURI dsUri; dsUri.setEncodedUri( uri ); gdalUri = ""; // prepareUri adds ? or & if necessary, GDAL fails otherwise - gdalUri += "" + QgsWcsCapabilities::prepareUri( dsUri.param("url") ) + ""; + gdalUri += "" + Qt::escape( QgsWcsCapabilities::prepareUri( dsUri.param("url") ) ) + ""; gdalUri += "" + dsUri.param("identifier") + ""; gdalUri += "" + dsUri.param("format") + ""; @@ -124,6 +127,7 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) // There is undocumented CRS tag, but it only overrides CRS param in requests // but BBOX is left unchanged and thus results in server error (usually). gdalUri += "&RESPONSE_CRS=" + dsUri.param("crs") + ""; + if ( dsUri.hasParam("username") && dsUri.hasParam("password") ) { gdalUri += "" + dsUri.param("username") + ":" + dsUri.param("password") + ""; diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp index c3b6e5133a2..1491f73e852 100644 --- a/src/providers/gdal/qgswcscapabilities.cpp +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -166,8 +166,17 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) if ( mCapabilitiesResponse.isNull() || forceRefresh ) { - // TODO: version - QString url = prepareUri( mUri.param("url") ) + "SERVICE=WCS&REQUEST=GetCapabilities"; + // Check if user tried to force version + QString userVersion = QUrl( mUri.param("url") ).queryItemValue("VERSION"); + if ( !userVersion.isEmpty() && !userVersion.startsWith("1.1.") ) + { + mErrorTitle = tr( "Version not supported" ); + mErrorFormat = "text/plain"; + mError = tr( "The version %1 specified in connection URL parameter VERSION is not supported by QGIS" ).arg( userVersion ); + return false; + } + + QString url = prepareUri( mUri.param("url") ) + "SERVICE=WCS&REQUEST=GetCapabilities&VERSION=1.1.0"; mError = ""; @@ -213,7 +222,7 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) if ( !domOK ) { // We had an Dom exception - - // mErrorCaption and mError are pre-filled by parseCapabilitiesDom + // mErrorTitle and mError are pre-filled by parseCapabilitiesDom mError += tr( "\nTried URL: %1" ).arg( url ); @@ -305,7 +314,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa if ( !contentSuccess ) { - mErrorCaption = tr( "Dom Exception" ); + mErrorTitle = tr( "Dom Exception" ); mErrorFormat = "text/plain"; mError = tr( "Could not get WCS capabilities: %1 at line %2 column %3\nThis is probably due to an incorrect WMS Server URL.\nResponse was:\n\n%4" ) .arg( errorMsg ) @@ -324,10 +333,12 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa QgsDebugMsg( "testing tagName " + docElem.tagName() ); if ( - docElem.tagName() != "Capabilities" + // We don't support 1.0, but try WCS_Capabilities tag to get version + docElem.tagName() != "WCS_Capabilities" && // 1.0 + docElem.tagName() != "Capabilities" // 1.1 ) { - mErrorCaption = tr( "Dom Exception" ); + mErrorTitle = tr( "Dom Exception" ); mErrorFormat = "text/plain"; mError = tr( "Could not get WCS capabilities in the expected format (DTD): no %1 found.\nThis might be due to an incorrect WMS Server URL.\nTag:%3\nResponse was:\n%4" ) .arg( "Capabilities" ) @@ -340,6 +351,20 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa } capabilities.version = docElem.attribute( "version" ); + mVersion = capabilities.version; + + if ( !mVersion.startsWith("1.1.") ) + { + mErrorTitle = tr( "Version not supported" ); + mErrorFormat = "text/plain"; + mError = tr( "Could not get WCS capabilities in the expected version 1.1.\nResponse version was: %1" ) + .arg( mVersion ); + + QgsLogger::debug( "WCS version: " + mError ); + + return false; + } + // Start walking through XML. QDomNode n = docElem.firstChild(); @@ -618,7 +643,7 @@ void QgsWcsCapabilities::coverageParents( QMap &parents, QMap coverages; if ( !mCapabilities.supportedCoverages( coverages ) ) - return false; + return; QMap items; QMap coverageParents; @@ -102,8 +105,6 @@ bool QgsWCSSourceSelect::populateLayerList( ) { mLayersTreeWidget->expandItem( mLayersTreeWidget->topLevelItem( 0 ) ); } - - return true; } void QgsWCSSourceSelect::addClicked( ) @@ -118,7 +119,7 @@ void QgsWCSSourceSelect::addClicked( ) uri.setParam( "identifier", identifier ); - uri.setParam( "crs", selectedCrs() ); + uri.setParam( "crs", selectedCRS() ); QgsDebugMsg ( "selectedFormat = " + selectedFormat() ); uri.setParam( "format", selectedFormat() ); @@ -139,7 +140,6 @@ void QgsWCSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged() void QgsWCSSourceSelect::updateButtons() { QgsDebugMsg ( "entered"); - //updateCRSWidgets(); if ( mLayersTreeWidget->selectedItems().isEmpty() ) { @@ -147,13 +147,13 @@ void QgsWCSSourceSelect::updateButtons() } else { - if ( mCRS.isEmpty() ) + if ( selectedCRS().isEmpty() ) { showStatusMessage( tr( "No CRS selected" ) ); } } - mAddButton->setEnabled( !mLayersTreeWidget->selectedItems().isEmpty() && !mCRS.isEmpty() && !selectedFormat().isEmpty() ); + mAddButton->setEnabled( !mLayersTreeWidget->selectedItems().isEmpty() && !selectedCRS().isEmpty() && !selectedFormat().isEmpty() ); } QList QgsWCSSourceSelect::providerFormats() @@ -199,7 +199,7 @@ QList QgsWCSSourceSelect::providerFormats() return formats; } -QStringList QgsWCSSourceSelect::serverFormats() +QStringList QgsWCSSourceSelect::selectedLayersFormats() { QgsDebugMsg ( "entered"); @@ -212,7 +212,7 @@ QStringList QgsWCSSourceSelect::serverFormats() return c.supportedFormat; } -QStringList QgsWCSSourceSelect::serverCRS() +QStringList QgsWCSSourceSelect::selectedLayersCRSs() { QgsDebugMsg ( "entered"); @@ -226,20 +226,6 @@ QStringList QgsWCSSourceSelect::serverCRS() return c.supportedCrs; } -QStringList QgsWCSSourceSelect::layerCRS( int id ) -{ - QVector coverages; - if ( !mCapabilities.supportedCoverages( coverages ) ) - foreach ( QgsWcsCoverageSummary c, coverages ) - { - if ( c.orderId == id ) - { - return c.supportedCrs; - } - } - return QStringList(); -} - void QgsWCSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item ) { // TODO: I am not convinced to disable layers according to selected CRS diff --git a/src/providers/gdal/qgswcssourceselect.h b/src/providers/gdal/qgswcssourceselect.h index 4dc06950d33..bfb4f4ad3cc 100644 --- a/src/providers/gdal/qgswcssourceselect.h +++ b/src/providers/gdal/qgswcssourceselect.h @@ -66,32 +66,15 @@ class QgsWCSSourceSelect : public QgsOWSSourceSelect private: QgsWcsCapabilities mCapabilities; - /** - * \brief Populate the layer list - private for now. - * - * \retval false if the layers could not be retrieved or parsed - - * see mWmsProvider->errorString() for more info - */ - bool populateLayerList( ); - - //! Add layer + // QgsWcsCapabilities virtual methods + void populateLayerList( ); void addClicked(); - - //! Signaled when a layer selection is changed. void on_mLayersTreeWidget_itemSelectionChanged(); - void enableLayersForCrs( QTreeWidgetItem *item ); - void updateButtons(); - QList providerFormats(); - - QStringList serverFormats(); - - QStringList serverCRS(); - - QStringList layerCRS( int id ); - + QStringList selectedLayersFormats(); + QStringList selectedLayersCRSs(); }; #endif // QGSWCSSOURCESELECT_H diff --git a/src/ui/qgsowssourceselectbase.ui b/src/ui/qgsowssourceselectbase.ui index 288b232f00d..d75cbb45ae8 100644 --- a/src/ui/qgsowssourceselectbase.ui +++ b/src/ui/qgsowssourceselectbase.ui @@ -53,7 +53,7 @@ true - 1 + 0 @@ -259,7 +259,7 @@ - + Coordinate Reference System From dce6b6c6791b7ec0be4c85974a024c03d2aa9fc2 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Thu, 26 Apr 2012 17:28:20 +0200 Subject: [PATCH 07/19] WCS - better versions and CRS --- src/gui/qgsowssourceselect.cpp | 29 +++-- src/providers/gdal/qgsgdalprovider.cpp | 48 ++++++-- src/providers/gdal/qgswcscapabilities.cpp | 140 +++++++--------------- src/providers/gdal/qgswcscapabilities.h | 75 +----------- src/providers/gdal/qgswcssourceselect.cpp | 87 ++++++++------ 5 files changed, 142 insertions(+), 237 deletions(-) diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp index ee114fff94d..07bcd150282 100644 --- a/src/gui/qgsowssourceselect.cpp +++ b/src/gui/qgsowssourceselect.cpp @@ -56,7 +56,7 @@ QgsOWSSourceSelect::QgsOWSSourceSelect( QString service, QWidget * parent, Qt::WFlags fl, bool managerMode, bool embeddedMode ) : QDialog( parent, fl ) - , mService ( service ) + , mService( service ) , mManagerMode( managerMode ) , mEmbeddedMode( embeddedMode ) , mCurrentTileset( 0 ) @@ -122,7 +122,7 @@ QgsOWSSourceSelect::~QgsOWSSourceSelect() void QgsOWSSourceSelect::populateFormats() { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); if ( mProviderFormats.size() == 0 ) { QHBoxLayout *layout = new QHBoxLayout; @@ -165,9 +165,9 @@ void QgsOWSSourceSelect::populateFormats() if ( firstVisible == -1 ) firstVisible = id; } // Set first if no one visible is checked - if ( mImageFormatGroup->checkedId() < 0 || ( !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() && firstVisible > -1 ) ) + if ( mImageFormatGroup->checkedId() < 0 || ( !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() && firstVisible > -1 ) ) { - mImageFormatGroup->button( firstVisible )->setChecked(true); + mImageFormatGroup->button( firstVisible )->setChecked( true ); } mImageFormatsGroupBox->setEnabled( true ); @@ -176,7 +176,7 @@ void QgsOWSSourceSelect::populateFormats() void QgsOWSSourceSelect::populateConnectionList() { mConnectionsComboBox->clear(); - mConnectionsComboBox->addItems( QgsOWSConnection::connectionList(mService) ); + mConnectionsComboBox->addItems( QgsOWSConnection::connectionList( mService ) ); setConnectionListPosition(); @@ -264,13 +264,13 @@ QgsNumericSortTreeWidgetItem *QgsOWSSourceSelect::createItem( const QMap &layerParents, const QMap &layerParentNames ) { - QgsDebugMsg( QString( "id = %1 layerAndStyleCount = %2 names = %3 ").arg( id).arg(layerAndStyleCount).arg(names.join(",") ) ); + QgsDebugMsg( QString( "id = %1 layerAndStyleCount = %2 names = %3 " ).arg( id ).arg( layerAndStyleCount ).arg( names.join( "," ) ) ); if ( items.contains( id ) ) return items[id]; QgsNumericSortTreeWidgetItem *item; - if ( layerParents.contains( id ) ) + if ( layerParents.contains( id ) ) { // it has parent -> create first its parent int parent = layerParents[ id ]; @@ -314,7 +314,7 @@ void QgsOWSSourceSelect::on_mConnectButton_clicked() void QgsOWSSourceSelect::addClicked() { - QgsDebugMsg( "entered"); + QgsDebugMsg( "entered" ); } void QgsOWSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item ) @@ -393,16 +393,15 @@ void QgsOWSSourceSelect::populateCRS() { // not found mSelectedCRS = defaultCRS; - mSelectedCRSLabel->setText( descriptionForAuthId( mSelectedCRS ) ); } - + mSelectedCRSLabel->setText( descriptionForAuthId( mSelectedCRS ) ); } else { mSelectedCRS = ""; mSelectedCRSLabel->setText( "" ); } - mChangeCRSButton->setEnabled( !mSelectedLayersCRSs.isEmpty() ); + mChangeCRSButton->setEnabled( !mSelectedLayersCRSs.isEmpty() ); } void QgsOWSSourceSelect::on_mTilesetsTableWidget_itemClicked( QTableWidgetItem *item ) @@ -498,7 +497,7 @@ void QgsOWSSourceSelect::showError( QString const &theTitle, QString const &theF } else { - mv->setMessageAsPlainText( tr( "Could not understand the response:\n%1" ).arg( theError) ); + mv->setMessageAsPlainText( tr( "Could not understand the response:\n%1" ).arg( theError ) ); } mv->showMessage( true ); // Is deleted when closed } @@ -717,9 +716,9 @@ void QgsOWSSourceSelect::on_mLayerDownButton_clicked() selectedItem->setSelected( true ); } -QList QgsOWSSourceSelect::providerFormats() -{ - return QList(); +QList QgsOWSSourceSelect::providerFormats() +{ + return QList(); } QStringList QgsOWSSourceSelect::selectedLayersFormats() diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index 61212833c47..ab959b20b05 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -110,27 +110,49 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) // The uri is either a file name or encoded parameters for WCS QString gdalUri = uri; - if ( uri.contains("url=") && uri.contains("identifier=") && !QFile::exists(uri) ) + if ( uri.contains( "url=" ) && uri.contains( "identifier=" ) && !QFile::exists( uri ) ) { - // WCS - // GDAL currently (4/2012) supports WCS 1.0.0 (default) and 1.1.0 + // - 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 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) // + QgsDataSourceURI dsUri; dsUri.setEncodedUri( uri ); gdalUri = ""; + gdalUri += "1.0.0"; // prepareUri adds ? or & if necessary, GDAL fails otherwise - gdalUri += "" + Qt::escape( QgsWcsCapabilities::prepareUri( dsUri.param("url") ) ) + ""; - gdalUri += "" + dsUri.param("identifier") + ""; - gdalUri += "" + dsUri.param("format") + ""; - - // TODO: There is no tag for CRS response. - // There is undocumented CRS tag, but it only overrides CRS param in requests - // but BBOX is left unchanged and thus results in server error (usually). - gdalUri += "&RESPONSE_CRS=" + dsUri.param("crs") + ""; + gdalUri += "" + Qt::escape( QgsWcsCapabilities::prepareUri( dsUri.param( "url" ) ) ) + ""; + gdalUri += "" + dsUri.param( "identifier" ) + ""; + gdalUri += "" + dsUri.param( "format" ) + ""; - if ( dsUri.hasParam("username") && dsUri.hasParam("password") ) + // - 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 += "" + dsUri.param("username") + ":" + dsUri.param("password") + ""; + gdalUri += "&RESPONSE_CRS=" + dsUri.param( "crs" ) + ""; + } + // 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 += "&GridBaseCRS=" + crsUrn + ""; + + if ( dsUri.hasParam( "username" ) && dsUri.hasParam( "password" ) ) + { + gdalUri += "" + dsUri.param( "username" ) + ":" + dsUri.param( "password" ) + ""; } gdalUri += ""; QgsDebugMsg( "WCS uri: " + gdalUri ); diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp index 1491f73e852..3082eeebf44 100644 --- a/src/providers/gdal/qgswcscapabilities.cpp +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -75,29 +75,22 @@ QgsWcsCapabilities::QgsWcsCapabilities( QString const &theUri ) */ QgsWcsCapabilities::QgsWcsCapabilities( QgsDataSourceURI const &theUri ): - mUri(theUri), - mCoverageCount(0) + mUri( theUri ), + mCoverageCount( 0 ) { QgsDebugMsg( "uri = " + mUri.encodedUri() ); - + retrieveServerCapabilities(); } QgsWcsCapabilities::QgsWcsCapabilities( ): - mCoverageCount(0) + mCoverageCount( 0 ) { } QgsWcsCapabilities::~QgsWcsCapabilities() { QgsDebugMsg( "deconstructing." ); -/* - if ( cacheReply ) - { - cacheReply->deleteLater(); - cacheReply = 0; - } -*/ } void QgsWcsCapabilities::setUri( QgsDataSourceURI const &theUri ) @@ -107,8 +100,8 @@ void QgsWcsCapabilities::setUri( QgsDataSourceURI const &theUri ) mCoveragesSupported.clear(); QgsWcsCapabilitiesProperty c; mCapabilities = c; - - retrieveServerCapabilities(true); + + retrieveServerCapabilities( true ); } QString QgsWcsCapabilities::prepareUri( QString uri ) @@ -142,20 +135,12 @@ bool QgsWcsCapabilities::supportedCoverages( QVector &cov return true; } -/* -QString QgsWcsCapabilities::baseUrl() const -{ - return prepareUri( mUri.param("url") ); -} -*/ - QString QgsWcsCapabilities::getCoverageUrl() const { QString url = mCapabilities.operationsMetadata.getCoverage.dcp.http.get.xlinkHref; - // TODO: ignore getCoverage url if ( url.isEmpty() ) { - url = mUri.param("url"); + url = mUri.param( "url" ); } return url; } @@ -167,8 +152,8 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) if ( mCapabilitiesResponse.isNull() || forceRefresh ) { // Check if user tried to force version - QString userVersion = QUrl( mUri.param("url") ).queryItemValue("VERSION"); - if ( !userVersion.isEmpty() && !userVersion.startsWith("1.1.") ) + QString userVersion = QUrl( mUri.param( "url" ) ).queryItemValue( "VERSION" ); + if ( !userVersion.isEmpty() && !userVersion.startsWith( "1.1." ) ) { mErrorTitle = tr( "Version not supported" ); mErrorFormat = "text/plain"; @@ -176,7 +161,7 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) return false; } - QString url = prepareUri( mUri.param("url") ) + "SERVICE=WCS&REQUEST=GetCapabilities&VERSION=1.1.0"; + QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities&VERSION=1.1.0"; mError = ""; @@ -230,7 +215,6 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) return false; } - } QgsDebugMsg( "exiting." ); @@ -288,9 +272,9 @@ void QgsWcsCapabilities::capabilitiesReplyProgress( qint64 bytesReceived, qint64 emit statusChanged( msg ); } -QString QgsWcsCapabilities::stripNS ( const QString & name ) +QString QgsWcsCapabilities::stripNS( const QString & name ) { - return name.contains( ":" ) ? name.section( ':', 1 ) : name; + return name.contains( ":" ) ? name.section( ':', 1 ) : name; } bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapabilitiesProperty &capabilities ) @@ -333,7 +317,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa QgsDebugMsg( "testing tagName " + docElem.tagName() ); if ( - // We don't support 1.0, but try WCS_Capabilities tag to get version + // We don't support 1.0, but try WCS_Capabilities tag to get version docElem.tagName() != "WCS_Capabilities" && // 1.0 docElem.tagName() != "Capabilities" // 1.1 ) @@ -353,7 +337,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa capabilities.version = docElem.attribute( "version" ); mVersion = capabilities.version; - if ( !mVersion.startsWith("1.1.") ) + if ( !mVersion.startsWith( "1.1." ) ) { mErrorTitle = tr( "Version not supported" ); mErrorFormat = "text/plain"; @@ -374,7 +358,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa QDomElement e = n.toElement(); // try to convert the node to an element. if ( !e.isNull() ) { - QString tagName = stripNS ( e.tagName() ); + QString tagName = stripNS( e.tagName() ); if ( tagName == "ServiceIdentification" ) { QgsDebugMsg( " ServiceIdentification." ); @@ -410,7 +394,7 @@ void QgsWcsCapabilities::parseServiceIdentification( QDomElement const & e, QgsW QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); + QString tagName = stripNS( el.tagName() ); if ( tagName == "Title" ) { @@ -437,11 +421,11 @@ void QgsWcsCapabilities::parseHttp( QDomElement const & e, QgsWcsHTTP& http ) QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); + QString tagName = stripNS( el.tagName() ); if ( tagName == "Get" ) { QgsDebugMsg( " Get." ); - http.get.xlinkHref = el.attribute( "xlink:href" ); + http.get.xlinkHref = el.attribute( "xlink:href" ); } } n1 = n1.nextSibling(); @@ -460,7 +444,7 @@ void QgsWcsCapabilities::parseDcp( QDomElement const & e, QgsWcsDCP& dcp ) QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); + QString tagName = stripNS( el.tagName() ); if ( tagName == "HTTP" ) { QgsDebugMsg( " HTTP." ); @@ -483,7 +467,7 @@ void QgsWcsCapabilities::parseOperation( QDomElement const & e, QgsWcsOperation& QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); + QString tagName = stripNS( el.tagName() ); if ( tagName == "DCP" ) { @@ -508,7 +492,7 @@ void QgsWcsCapabilities::parseOperationsMetadata( QDomElement const & e, QgsWcs QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); + QString tagName = stripNS( el.tagName() ); if ( tagName == "GetCoverage" ) { @@ -524,7 +508,7 @@ void QgsWcsCapabilities::parseOperationsMetadata( QDomElement const & e, QgsWcs void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCoverageSummary &coverageSummary, QgsWcsCoverageSummary *parent ) { - QgsDebugMsg("entering."); + QgsDebugMsg( "entering." ); coverageSummary.orderId = ++mCoverageCount; @@ -534,8 +518,8 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); - QgsDebugMsg( tagName + " : " + el.text()); + QString tagName = stripNS( el.tagName() ); + QgsDebugMsg( tagName + " : " + el.text() ); if ( tagName == "Identifier" ) { @@ -559,10 +543,10 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove // TODO: SupportedCRS may be URL referencing a document // URN format: urn:ogc:def:objectType:authority:version:code // URN example: urn:ogc:def:crs:EPSG::4326 - QStringList urn = el.text().split(":"); - if ( urn.size() == 7 ) + QStringList urn = el.text().split( ":" ); + if ( urn.size() == 7 ) { - coverageSummary.supportedCrs << urn.value(4) + ":" + urn.value(6); + coverageSummary.supportedCrs << urn.value( 4 ) + ":" + urn.value( 6 ); } } else if ( tagName == "WGS84BoundingBox" ) @@ -574,10 +558,10 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove double w, e, s, n; bool wOk, eOk, sOk, nOk; - w = lower.value(0).toDouble( &wOk ); - s = lower.value(1).toDouble( &sOk ); - e = upper.value(0).toDouble( &eOk ); - n = upper.value(1).toDouble( &nOk ); + w = lower.value( 0 ).toDouble( &wOk ); + s = lower.value( 1 ).toDouble( &sOk ); + e = upper.value( 0 ).toDouble( &eOk ); + n = upper.value( 1 ).toDouble( &nOk ); if ( wOk && eOk && sOk && nOk ) { coverageSummary.wgs84BoundingBox = QgsRectangle( w, s, e, n ); @@ -594,7 +578,7 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove QDomElement el = n1.toElement(); // try to convert the node to an element. if ( !el.isNull() ) { - QString tagName = stripNS ( el.tagName() ); + QString tagName = stripNS( el.tagName() ); if ( tagName == "CoverageSummary" ) { @@ -616,7 +600,7 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove if ( parent && parent->orderId > 1 ) // ignore Contents to put them on top level { - QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2 has parent %3").arg(coverageSummary.orderId).arg(coverageSummary.identifier).arg(parent->orderId) ); + QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2 has parent %3" ).arg( coverageSummary.orderId ).arg( coverageSummary.identifier ).arg( parent->orderId ) ); mCoverageParents[ coverageSummary.orderId ] = parent->orderId; } @@ -630,9 +614,9 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove { mCoverageParentIdentifiers[ coverageSummary.orderId ] = QStringList() << coverageSummary.identifier << coverageSummary.title << coverageSummary.abstract; } - QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2").arg(coverageSummary.orderId).arg(coverageSummary.identifier) ); + QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2" ).arg( coverageSummary.orderId ).arg( coverageSummary.identifier ) ); - QgsDebugMsg("exiting."); + QgsDebugMsg( "exiting." ); } void QgsWcsCapabilities::coverageParents( QMap &parents, QMap &parentNames ) const @@ -659,56 +643,14 @@ QString QgsWcsCapabilities::lastErrorFormat() void QgsWcsCapabilities::setAuthorization( QNetworkRequest &request ) const { - if ( mUri.hasParam("username") && mUri.hasParam("password") ) + QgsDebugMsg( "entered" ); + if ( mUri.hasParam( "username" ) && mUri.hasParam( "password" ) ) { - request.setRawHeader( "Authorization", "Basic " + QString( "%1:%2" ).arg( mUri.param("username") ).arg( mUri.param("password") ).toAscii().toBase64() ); + QgsDebugMsg( "setAuthorization " + mUri.param( "username" ) ); + request.setRawHeader( "Authorization", "Basic " + QString( "%1:%2" ).arg( mUri.param( "username" ) ).arg( mUri.param( "password" ) ).toAscii().toBase64() ); } } -// TOD: GDAL supported formats? -/* -QVector QgsWcsCapabilities::supportedFormats() -{ - QVector formats; - QStringList mFormats, mLabels; - - - QList supportedFormats = QImageReader::supportedImageFormats(); - - if ( supportedFormats.contains( "png" ) ) - { - QgsWcsSupportedFormat p1 = { "image/png", "PNG" }; - QgsWcsSupportedFormat p2 = { "image/png; mode=24bit", "PNG24" }; // UMN mapserver - QgsWcsSupportedFormat p3 = { "image/png8", "PNG8" }; // used by geoserver - QgsWcsSupportedFormat p4 = { "png", "PNG" }; // used by french IGN geoportail - QgsWcsSupportedFormat p5 = { "pngt", "PNGT" }; // used by french IGN geoportail - - formats << p1 << p2 << p3 << p4 << p5; - } - - if ( supportedFormats.contains( "jpg" ) ) - { - QgsWcsSupportedFormat j1 = { "image/jpeg", "JPEG" }; - QgsWcsSupportedFormat j2 = { "jpeg", "JPEG" }; // used by french IGN geoportail - formats << j1 << j2; - } - - if ( supportedFormats.contains( "gif" ) ) - { - QgsWcsSupportedFormat g1 = { "image/gif", "GIF" }; - formats << g1; - } - - if ( supportedFormats.contains( "tiff" ) ) - { - QgsWcsSupportedFormat t1 = { "image/tiff", "TIFF" }; - formats << t1; - } - - return formats; -} -*/ - void QgsWcsCapabilities::showMessageBox( const QString& title, const QString& text ) { QgsMessageOutput *message = QgsMessageOutput::createMessageOutput(); @@ -717,9 +659,9 @@ void QgsWcsCapabilities::showMessageBox( const QString& title, const QString& te message->showMessage(); } -QgsWcsCoverageSummary QgsWcsCapabilities::coverageSummary ( QString const & theIdentifier ) +QgsWcsCoverageSummary QgsWcsCapabilities::coverageSummary( QString const & theIdentifier ) { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); foreach( QgsWcsCoverageSummary c, mCoveragesSupported ) { if ( c.identifier == theIdentifier ) return c; diff --git a/src/providers/gdal/qgswcscapabilities.h b/src/providers/gdal/qgswcscapabilities.h index f3d4624f0b8..05466b66698 100644 --- a/src/providers/gdal/qgswcscapabilities.h +++ b/src/providers/gdal/qgswcscapabilities.h @@ -160,19 +160,9 @@ class QgsWcsCapabilities : public QObject * \brief Returns a map for the hierarchy of layers */ void coverageParents( QMap &parents, QMap &parentNames ) const; - + //! Get coverage summare for identifier - QgsWcsCoverageSummary coverageSummary ( QString const & theIdentifier ); - - /** - * Set the name of the connection for use in authentication where required - * \note added in 1.1 - */ - //void setConnectionName( QString const & connName ); - - /**Returns the base url - */ - //QString baseUrl() const; + QgsWcsCoverageSummary coverageSummary( QString const & theIdentifier ); /** * \brief Prepare the URI so that we can later simply append param=value @@ -189,12 +179,6 @@ class QgsWcsCapabilities : public QObject //! set authorization header void setAuthorization( QNetworkRequest &request ) const; - //! get WCS Server version string - //QString wmsVersion(); - - //! get raster image encodings supported by the WCS Server, expressed as MIME types - //QStringList supportedImageEncodings(); - /** * \brief Returns the caption error text for the last error in this provider * @@ -220,8 +204,6 @@ class QgsWcsCapabilities : public QObject */ QString lastErrorFormat(); - //static QVector supportedFormats(); - signals: /** \brief emit a signal to notify of a progress event */ @@ -238,7 +220,7 @@ class QgsWcsCapabilities : public QObject void showMessageBox( const QString& title, const QString& text ); //! Get tag name without namespace - QString stripNS ( const QString & name ); + QString stripNS( const QString & name ); /** * \brief Retrieve and parse the (cached) Capabilities document from the server @@ -274,33 +256,11 @@ class QgsWcsCapabilities : public QObject //! parse the WCS Layer XML element void parseCoverageSummary( QDomElement const &e, QgsWcsCoverageSummary &coverageSummary, - QgsWcsCoverageSummary *parent = 0 ); - - //! parse the WCS Layer XML element - //void parseContents( QDomElement const &e, QgsWcsContents &contents ); - - /** - * \brief parse the full WCS ServiceExceptionReport XML document - * - * \note mErrorCaption and mError are updated to suit the results of this function. - */ - //bool parseServiceExceptionReportDom( QByteArray const &xml ); - - //! parse the WCS ServiceException XML element - //void parseServiceException( QDomElement const &e ); - - //! Data source URI of the WCS for this layer - //QString httpuri; - - //! Name of the stored connection - //QString connectionName; + QgsWcsCoverageSummary *parent = 0 ); //! Data source uri QgsDataSourceURI mUri; - //! URL part of URI (httpuri) - //QString mBaseUrl; - //! Response capabilities version QString mVersion; @@ -329,21 +289,6 @@ class QgsWcsCapabilities : public QObject */ QVector mCoveragesSupported; - /** - * extents per layer (in WCS CRS:84 datum) - */ - //QMap extentForLayer; - - /** - * available CRSs per layer - */ - //QMap mCrsForLayer; - - /** - * available formats per layer - */ - //QMap mFormatForLayer; - /** * The reply to the capabilities request */ @@ -363,12 +308,6 @@ class QgsWcsCapabilities : public QObject */ QString mErrorFormat; - //! A QgsCoordinateTransform is used for transformation of WCS layer extents - //QgsCoordinateTransform *mCoordinateTransform; - - //! See if calculateExtents() needs to be called before extent() returns useful data - //bool extentDirty; - int mCoverageCount; //! number of layers and parents @@ -380,12 +319,6 @@ class QgsWcsCapabilities : public QObject //! Password for basic http authentication QString mPassword; - - //! whether to use hrefs from GetCapabilities (default) or - // the given base urls for GetMap and GetFeatureInfo - //bool mIgnoreGetCoverageUrl; - - }; diff --git a/src/providers/gdal/qgswcssourceselect.cpp b/src/providers/gdal/qgswcssourceselect.cpp index 6db0283d57d..e1e9fbe0f2f 100644 --- a/src/providers/gdal/qgswcssourceselect.cpp +++ b/src/providers/gdal/qgswcssourceselect.cpp @@ -37,28 +37,30 @@ #endif QgsWCSSourceSelect::QgsWCSSourceSelect( QWidget * parent, Qt::WFlags fl, bool managerMode, bool embeddedMode ) - : QgsOWSSourceSelect ( "WCS", parent, fl, managerMode, embeddedMode ) + : QgsOWSSourceSelect( "WCS", parent, fl, managerMode, embeddedMode ) { - // Hide irrelevant widgets + // Hide irrelevant widgets mWMSGroupBox->hide(); - mLayersTab->layout()->removeWidget ( mWMSGroupBox ); + 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 ); + + mLayersTreeWidget->setSelectionMode( QAbstractItemView::SingleSelection ); } QgsWCSSourceSelect::~QgsWCSSourceSelect() { } -void QgsWCSSourceSelect::populateLayerList( ) +void QgsWCSSourceSelect::populateLayerList( ) { QgsDebugMsg( "entered" ); - mCapabilities.setUri ( mUri ); + mLayersTreeWidget->clear(); + + mCapabilities.setUri( mUri ); if ( !mCapabilities.lastError().isEmpty() ) { @@ -69,13 +71,12 @@ void QgsWCSSourceSelect::populateLayerList( ) QVector coverages; if ( !mCapabilities.supportedCoverages( coverages ) ) return; - + QMap items; QMap coverageParents; QMap coverageParentNames; mCapabilities.coverageParents( coverageParents, coverageParentNames ); - mLayersTreeWidget->clear(); mLayersTreeWidget->setSortingEnabled( true ); int coverageAndStyleCount = -1; @@ -84,7 +85,7 @@ void QgsWCSSourceSelect::populateLayerList( ) coverage != coverages.end(); coverage++ ) { - QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2").arg(coverage->orderId).arg(coverage->identifier) ); + 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 ); @@ -109,37 +110,45 @@ void QgsWCSSourceSelect::populateLayerList( ) void QgsWCSSourceSelect::addClicked( ) { - QgsDebugMsg ( "entered"); - QgsDataSourceURI uri = mUri; - + QgsDebugMsg( "entered" ); + QgsDataSourceURI uri = mUri; + QList selectionList = mLayersTreeWidget->selectedItems(); if ( selectionList.size() < 1 ) return; // should not happen - QString identifier = selectionList.value(0)->data( 0, Qt::UserRole + 0 ).toString(); - QgsDebugMsg ( " identifier = " + identifier ); + QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString(); + QgsDebugMsg( " identifier = " + identifier ); uri.setParam( "identifier", identifier ); - uri.setParam( "crs", selectedCRS() ); - - QgsDebugMsg ( "selectedFormat = " + selectedFormat() ); - uri.setParam( "format", selectedFormat() ); + // 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() ); + uri.setParam( "format", selectedFormat() ); emit addRasterLayer( uri.encodedUri(), identifier, "gdal" ); } void QgsWCSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged() { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); populateFormats(); populateCRS(); - mAddButton->setEnabled(true); + updateButtons(); + + mAddButton->setEnabled( true ); } void QgsWCSSourceSelect::updateButtons() { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); if ( mLayersTreeWidget->selectedItems().isEmpty() ) { @@ -158,16 +167,16 @@ void QgsWCSSourceSelect::updateButtons() QList QgsWCSSourceSelect::providerFormats() { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); QList formats; GDALAllRegister(); - QgsDebugMsg ( QString( "GDAL drivers cont %1").arg(GDALGetDriverCount()) ); + 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 ) ); @@ -176,7 +185,7 @@ QList QgsWCSSourceSelect::providerFormats() QString desc = GDALGetDescription( driver ); - QString mimeType = GDALGetMetadataItem ( driver, "DMD_MIMETYPE", "" ); + QString mimeType = GDALGetMetadataItem( driver, "DMD_MIMETYPE", "" ); if ( mimeType.isEmpty() ) continue; @@ -184,15 +193,15 @@ QList QgsWCSSourceSelect::providerFormats() QgsOWSSupportedFormat format = { mimeType, desc }; - QgsDebugMsg ( "add GDAL format " + mimeType + " " + desc ); + QgsDebugMsg( "add GDAL format " + mimeType + " " + desc ); if ( mimeType == "image/tiff" ) { - formats.prepend ( format ); + formats.prepend( format ); } else { - formats.append ( format ); + formats.append( format ); } } @@ -201,27 +210,27 @@ QList QgsWCSSourceSelect::providerFormats() QStringList QgsWCSSourceSelect::selectedLayersFormats() { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); QList selectionList = mLayersTreeWidget->selectedItems(); if ( selectionList.size() < 1 ) return QStringList(); - QString identifier = selectionList.value(0)->data( 0, Qt::UserRole + 0 ).toString(); - QgsDebugMsg ( " identifier = " + identifier ); - - QgsWcsCoverageSummary c = mCapabilities.coverageSummary(identifier); - return c.supportedFormat; + QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString(); + QgsDebugMsg( " identifier = " + identifier ); + + QgsWcsCoverageSummary c = mCapabilities.coverageSummary( identifier ); + return c.supportedFormat; } QStringList QgsWCSSourceSelect::selectedLayersCRSs() { - QgsDebugMsg ( "entered"); + QgsDebugMsg( "entered" ); QList selectionList = mLayersTreeWidget->selectedItems(); if ( selectionList.size() < 1 ) return QStringList(); - QString identifier = selectionList.value(0)->data( 0, Qt::UserRole + 0 ).toString(); - QgsDebugMsg ( " identifier = " + identifier ); + QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString(); + QgsDebugMsg( " identifier = " + identifier ); - QgsWcsCoverageSummary c = mCapabilities.coverageSummary(identifier); + QgsWcsCoverageSummary c = mCapabilities.coverageSummary( identifier ); return c.supportedCrs; } From edfeba11f33ac40fc0272496413fb5140ad833e6 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Sat, 28 Apr 2012 08:54:15 +0200 Subject: [PATCH 08/19] explanation of various bugs in GDAL and Mapserver --- src/gui/qgsowssourceselect.cpp | 7 +++-- src/providers/gdal/qgsgdalprovider.cpp | 38 ++++++++++++++++------- src/providers/gdal/qgswcscapabilities.cpp | 5 +-- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp index 07bcd150282..31441d49685 100644 --- a/src/gui/qgsowssourceselect.cpp +++ b/src/gui/qgsowssourceselect.cpp @@ -165,9 +165,12 @@ void QgsOWSSourceSelect::populateFormats() if ( firstVisible == -1 ) firstVisible = id; } // Set first if no one visible is checked - if ( mImageFormatGroup->checkedId() < 0 || ( !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() && firstVisible > -1 ) ) + if ( mImageFormatGroup->checkedId() < 0 || !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() ) { - mImageFormatGroup->button( firstVisible )->setChecked( true ); + if ( firstVisible > -1 ) + { + mImageFormatGroup->button( firstVisible )->setChecked( true ); + } } mImageFormatsGroupBox->setEnabled( true ); diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index ab959b20b05..07d7f1dd9e9 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -25,6 +25,7 @@ #include "qgscoordinatetransform.h" #include "qgsdataitem.h" #include "qgsdatasourceuri.h" +#include "qgsmessagelog.h" #include "qgsrectangle.h" #include "qgscoordinatereferencesystem.h" #include "qgsrasterbandstats.h" @@ -116,21 +117,32 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) // 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 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) - // + // - 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 = ""; gdalUri += "1.0.0"; + //gdalUri += "1.1.0"; // prepareUri adds ? or & if necessary, GDAL fails otherwise gdalUri += "" + Qt::escape( QgsWcsCapabilities::prepareUri( dsUri.param( "url" ) ) ) + ""; gdalUri += "" + dsUri.param( "identifier" ) + ""; @@ -158,13 +170,15 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) QgsDebugMsg( "WCS uri: " + gdalUri ); } + CPLErrorReset(); //mGdalBaseDataset = GDALOpen( QFile::encodeName( uri ).constData(), GA_ReadOnly ); mGdalBaseDataset = GDALOpen( TO8F( gdalUri ), GA_ReadOnly ); - CPLErrorReset(); if ( mGdalBaseDataset == NULL ) { - QgsDebugMsg( QString( "Cannot open GDAL dataset %1: %2" ).arg( uri ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) ); + QString msg = QString( "Cannot open GDAL dataset %1:\n%2" ).arg( uri ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ); + QgsDebugMsg( msg ); + QgsMessageLog::logMessage( msg ); return; } diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp index 3082eeebf44..6d55bd9eb68 100644 --- a/src/providers/gdal/qgswcscapabilities.cpp +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -316,10 +316,11 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa // Assert that the DTD is what we expected (i.e. a WCS Capabilities document) QgsDebugMsg( "testing tagName " + docElem.tagName() ); + QString tagName = stripNS( docElem.tagName() ); if ( // We don't support 1.0, but try WCS_Capabilities tag to get version - docElem.tagName() != "WCS_Capabilities" && // 1.0 - docElem.tagName() != "Capabilities" // 1.1 + tagName != "WCS_Capabilities" && // 1.0 + tagName != "Capabilities" // 1.1, tags seen: Capabilities, wcs:Capabilities ) { mErrorTitle = tr( "Dom Exception" ); From 297d0bdf1cf79ba0912713dfeba0180bd8d91aef Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Sat, 28 Apr 2012 09:40:16 +0200 Subject: [PATCH 09/19] gis theme add WCS layer icon --- images/images.qrc | 1 + images/themes/gis/mActionAddWcsLayer.png | Bin 0 -> 948 bytes 2 files changed, 1 insertion(+) create mode 100644 images/themes/gis/mActionAddWcsLayer.png diff --git a/images/images.qrc b/images/images.qrc index 603b0c4a8cf..76ef7dffa4a 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -246,6 +246,7 @@ themes/gis/mActionAddSpatiaLiteLayer.png themes/gis/mActionAddVertex.png themes/gis/mActionAddWfsLayer.png + themes/gis/mActionAddWcsLayer.png themes/gis/mActionAddWmsLayer.png themes/gis/mActionAlignBottom.png themes/gis/mActionAlignHCenter.png diff --git a/images/themes/gis/mActionAddWcsLayer.png b/images/themes/gis/mActionAddWcsLayer.png new file mode 100644 index 0000000000000000000000000000000000000000..119f8b68e1da1ce565e2c34c4bcf1def15691113 GIT binary patch literal 948 zcmV;l155mgP)EWaQ_$K97!)YP2vs2%gBV4lC=ug= zRYM>l#*M+9!G%A9y0jaE(L|%H*viH)Rz|@{ZCMB+RXfmWYuo9^3^N@Urp-*LP~fcI zz3<$6a^Jo4-cY)(V<+%5@17%sdwJ=?+4|->2az{65KiO}3@*ZM zw}YZ6Ef5F_s;UmXeljs@jJ0f+{Ho{nK0>&cH?Cc2IMsfXd1Kz%cHfW6)WFY z;5gtQJw0a{XqtY}J95XqBZ0iFX7YsFUFUWkhJPu9mC#QR3jqKSn!w6ik8!~ALHX9G8(@9vC?ecg$ zq|kWUNFE#`ir^cQe z6p>1%;A(LJ0Q_J5(OgzqEbz8%@^(n4)8Kh)(M}~(N}aM6DA=^m=hMf=#;Ahh(afAF z!OYBz$)1|HZ?Yvxg2Uki0EnWfDT*?0{Id5{fu?H6q%+{HRw#;sKp-f{vNUSsY}teD zu(Z5{W>+&}u_(Rs+Kh>dthjFb;L^zmI+u$=e;3r*qJ;Wp5O#z5x)^7%YoExdxNsYs*~ z-9kL<-L=4KbQK-Vov>K`%}Jx95dgpt1`J`q(Hw+$xO-1iR7k$n-lhsl=X@*l9q&Vv zv&rPUb@3JeAQTPZ^YZ-O#x$Oc;ZSvb*}e7n8i0}trl+TOBry4QvbdfYo&W&cdw$Qv zDGC^`i%Kx-ovr9Gr-Aa1O$DMK0CX3Oh0sFrr89CW{;Md(uy^=81 Date: Sat, 28 Apr 2012 12:18:17 +0200 Subject: [PATCH 10/19] show correct service in connection title --- src/gui/qgsnewhttpconnection.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/qgsnewhttpconnection.cpp b/src/gui/qgsnewhttpconnection.cpp index 0389ca58b9f..279093f923b 100644 --- a/src/gui/qgsnewhttpconnection.cpp +++ b/src/gui/qgsnewhttpconnection.cpp @@ -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. @@ -65,7 +68,8 @@ QgsNewHttpConnection::QgsNewHttpConnection( // Adjust height int w = width(); adjustSize(); - resize(w, height()); + resize( w, height() ); + } on_txtName_textChanged( connName ); From 99cfa7c4116aea7f61ab3abfcf2453ce2b343c88 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Sat, 28 Apr 2012 12:20:21 +0200 Subject: [PATCH 11/19] WCS gis theme icons --- images/images.qrc | 2 ++ images/themes/default/mIconWcs.png | Bin 0 -> 2700 bytes images/themes/gis/mIconWcs.png | Bin 0 -> 992 bytes 3 files changed, 2 insertions(+) create mode 100644 images/themes/default/mIconWcs.png create mode 100644 images/themes/gis/mIconWcs.png diff --git a/images/images.qrc b/images/images.qrc index 76ef7dffa4a..23c8f21c5ce 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -191,6 +191,7 @@ themes/default/mIconUnknownLayerType.png themes/default/mIconWaitingForLayerType.png themes/default/mIconWfs.png + themes/default/mIconWcs.png themes/default/mIconWms.png themes/default/mIconWmsLayer.png themes/default/mIconWarn.png @@ -368,6 +369,7 @@ themes/default/plugins/north_arrow.png themes/default/plugins/scale_bar.png themes/default/mActionAddWfsLayer.png + themes/gis/mIconWcs.png themes/gis/mIconWms.png themes/gis/mIconWfs.png themes/gis/mIconSpatialite.png diff --git a/images/themes/default/mIconWcs.png b/images/themes/default/mIconWcs.png new file mode 100644 index 0000000000000000000000000000000000000000..71b2c8d88ba68e98a38ede431eacd32bd90e5fbb GIT binary patch literal 2700 zcmV;73Ul>|P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00VXa00VXbebs`@00007bV*G`2iyc4 z2onm)PQfPt016CAL_t(o!;P1Dj9t}z$3N%X<=uDReQ(|}Z+3geW{f@d*dAjO6O7pm z1Tcw%NvlGkjT&N7q7tQPg-TR4X_cxM0#KfKMqYwu%0W7EBe zU>FLm6iNgD0c=C}Kl{)%cPgbu-^;4%H+`^e$H#Z~^{u<@eb=sEyJcfnt`zrrW&+g} z1_1|O9$;`eWYxyCAcBZsC^hdo*7M`@#p=4ObNVa$xBOfw^{XqbZ(eC4)wDl%?}x76 z>^j!N9qo<#I@yuWGp?KkYbdH3eO>b|P2eeIf7TACUp9*?07t*TX@xw!(# zT$-2r&+_-*_)knjqqQaoBM{+_AG}F+_I9dj&8I7$AZ{CvTekDX-|T_J-ktY-WcLHR zc5b-u`fE3|Wzrsg5HdAez_!ZFEiALJxJ)+fk<6v>gAm^jc-vM5!2p8C!q-X5MN*_a{M zw+X8jl59&7h9RSKWkf)bE`cxQJo~S;(k}va0DB((hwhpA!o8(ZtuKD&ho_k>R2UwcW3g1FGP6MKoGLI=@-b}-f(Q{oYYn#M zTQ9tUL=iF9p=nz$LClfv2Fq;othKdT(EiG6!zrfl&Fc<4V~5(vVp%BLLJLG%Q4EFg z~+Y<}CbaasZGgCA+xQxvd2(&>phzLR<5{ROZ$gdzF+_HTg5AEGS zRhyWW$(fO9{`~3ZSt^u2A4Xvcc*2~0{bSeGJUY0TyToT zWG_l8;D;!{h{pjqa(13KCy(&Sd-_PkW8^X(58u0!UmhRrKQ=UT=I4Mua$-u9GC=A2 ztu?pb-NehYqbQ|ON?~Ztr_))2kygx%O`{uF~SH+wUBBkYfRf}1JG|x)GA{$%PXiM?b#gDGb<=#QzFgp<~u1*hIQ%{ z5Zl7rl4kJGSK0SI#m8>z<)+Q6QMOHJTBulzz_2(yQ>0i8NxBxcsi{UPRSs1Gz|>7$ zC!c)rwXN${r$E&?T|`*S_#9iz(VNVlhw+JQ18+>mdAr50gNOvTCyVq7|MHnn^X2D$ zz?zoTXxnCBe2KYY6~i((I<|zbG~G=pGI5J?BvmmCAHe9j^TDoS`OpnUXO(5A#IjSO z=#&W3RpzE^+~9VgwV<_N7|>JGf(Q7F?KcN}XP zKp&Z|4Ai7!x?Bq{0bn&p9IT$WOD467$5Z5{=$0jovJWN50Q<-~9$_ z8a=LCljFwjJRLcYbjp=XgGKYwuh<}@0Gh(c>X z6#cb17Ap~+X`ct6fro+}JaK%KN+OP+SwJI7Au*rN|HWt6e$5Wn^=u?SkxP}C51}Du zl1Vxgs^Oah^M$w1)A3bzKlsXtKmDhBe(!-kmGqny)@EiAH3r>UO3#(nX-jpTckZvaZ`gfM49T?zkOuW*>{X#IE?+f zyQ*jKXGfqRk2ScUk^u^xf>?2!_rrTCO`}(O_xtwI&cV{C%oF3ub+tktqpEN>ZixY^_ zbr2{-DXdMmGw*fskB@&sxsI)zn2j>c!4pgV*Zym&JbZ~LO+Wgj^-VwdyMYJp-mXkT zqtpd|3vlvuh0RWGMHuRR#qnyHp@vpKpPM_E*+q!XzCpTY8`nPa#NvE4eD=xf8V_7i z6|d{QdgN0deV`+58<&K_4+LtOnAVpFYeATcguslgSXLAeMI3(h5dOAXe-Yex|6@Pe zlRvg1#1{`n&JKTVY;syIC)6!dQ6s#ps#hqIfQrJEKL^kT*X(#dvp@aj?jP;RFI=+6 zE*?}Wm9M@ra2%1#R||#-eiU7H&ej?y@-JU)7#4Sa;2xuALr*{8{C{=9*x}PF>jqPq0gbVvb33c5V@zbg>o9zTu&nJ;m=Z>eM;x;FgJ@jL#mG)e* zFc}*keQJEJ`7b|u+j>J#@3KZQK3QN}F-cq8dzZEKPS&5}PpnmxGOH1#SL6rD?=m?1 z=ylAGd=9_zxl2NDj%UCB+R@WtEr{yo)%A3}i?ILZ90wOCRvr;~ho6OA4O#9Q{%<6x zA%PEpkAyxF_=teo_XQViJr3-;Vr{4`=a~)d@wM-$;7H`6R*V!~g&Q7<5HgbU}4=Xm4@= zQg32qa&#b5dSiNJaA9s`YhPBe2mk;87<5HgbVG7wVRUJ4ZXi@?ZDjy5FflSMFf=VP zIO7MX-T(jqQglUFbVF}&d2(rIXmkKWLm)wPbaH88b#!TOZY@)2VRB_bY-wv{AZT=S za5^t9V{&C-bZK^FV{dJ3Z*FrgZ*pfZY-wXxiv?18E`v03s47s)9^53rUjT_4c&Ovi7_@UMxKX0)eVp znWhQ5(u^+88RRHKJh25uQ7t~2rXia#plK>xE*Fs`sn75ClTzcwa_5ne5lisbjh|SI zzlJQ?kW3k%ltPx9Ek3HMBArU_*)8@KDQ>vE06tU!D)l3g#LmtyEWCMZS&xRd!3rFV zb8yZpEwQEth}UN7?}|a%3}EsEPu{7$T8qoKj=F+~ Date: Sat, 28 Apr 2012 12:21:13 +0200 Subject: [PATCH 12/19] WCS data items (browser support) --- src/providers/gdal/qgsgdaldataitems.cpp | 239 +++++++++++++++++++++- src/providers/gdal/qgsgdaldataitems.h | 60 ++++++ src/providers/gdal/qgsgdalprovider.cpp | 32 +++ src/providers/gdal/qgsgdalprovider.h | 2 + src/providers/gdal/qgswcscapabilities.cpp | 5 + src/providers/gdal/qgswcscapabilities.h | 2 + src/providers/gdal/qgswcssourceselect.cpp | 30 +-- 7 files changed, 344 insertions(+), 26 deletions(-) diff --git a/src/providers/gdal/qgsgdaldataitems.cpp b/src/providers/gdal/qgsgdaldataitems.cpp index d7ed36db458..a90822a748c 100644 --- a/src/providers/gdal/qgsgdaldataitems.cpp +++ b/src/providers/gdal/qgsgdaldataitems.cpp @@ -1,8 +1,10 @@ #include "qgsgdaldataitems.h" #include "qgsgdalprovider.h" #include "qgslogger.h" -//#include "qgsowssourceselect.h" +#include "qgsdatasourceuri.h" #include "qgswcssourceselect.h" +#include "qgsowsconnection.h" +#include "qgsnewhttpconnection.h" #include @@ -54,6 +56,236 @@ bool QgsGdalLayerItem::setCrs( QgsCoordinateReferenceSystem crs ) return true; } +// --------------------------------------------------------------------------- +QgsWCSConnectionItem::QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path ) + : QgsDataCollectionItem( parent, name, path ) +{ + mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) ); +} + +QgsWCSConnectionItem::~QgsWCSConnectionItem() +{ +} + +QVector QgsWCSConnectionItem::createChildren() +{ + QgsDebugMsg( "Entered" ); + QVector children; + + QgsOWSConnection connection( "WCS", mName ); + + QgsDataSourceURI uri = connection.uri(); + QgsDebugMsg( "uri = " + uri.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" ) ); + 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( other ); + //TODO + //return ( mPath == o->mPath && mName == o->mName && mConnInfo == o->mConnInfo ); + return false; +} + +QList QgsWCSConnectionItem::actions() +{ + QList 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(); + } + 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 ); + + 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; + } + } + } + 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 ); + } + 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() +{ +} + +QVectorQgsWCSRootItem::createChildren() +{ + QVector connections; + foreach( QString connName, QgsOWSConnection::connectionList( "WCS" ) ) + { + QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, mPath + "/" + connName ); + connections.append( conn ); + } + return connections; +} + +QList QgsWCSRootItem::actions() +{ + QList 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(); + } +} + // --------------------------------------------------------------------------- @@ -68,7 +300,10 @@ QGISEXTERN int dataCapabilities() QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) { if ( thePath.isEmpty() ) - return 0; + { + // Top level WCS + return new QgsWCSRootItem( parentItem, "WCS", "wcs:" ); + } QFileInfo info( thePath ); if ( info.isFile() ) diff --git a/src/providers/gdal/qgsgdaldataitems.h b/src/providers/gdal/qgsgdaldataitems.h index fef1a4126ce..33f4c243900 100644 --- a/src/providers/gdal/qgsgdaldataitems.h +++ b/src/providers/gdal/qgsgdaldataitems.h @@ -2,6 +2,9 @@ #define QGSGDALDATAITEMS_H #include "qgsdataitem.h" +#include "qgsdatasourceuri.h" +//#include "qgsowsconnection.h" +#include "qgswcscapabilities.h" class QgsGdalLayerItem : public QgsLayerItem { @@ -14,5 +17,62 @@ class QgsGdalLayerItem : public QgsLayerItem Capability capabilities(); }; +class QgsWCSConnectionItem : public QgsDataCollectionItem +{ + Q_OBJECT + public: + QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path ); + ~QgsWCSConnectionItem(); + + QVector createChildren(); + virtual bool equal( const QgsDataItem *other ); + + virtual QList actions(); + + QgsWcsCapabilities mCapabilities; + //QgsDataSourceURI mUri; + //QgsOWSConnection mConnection; + QVector 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 createChildren(); + + virtual QList actions(); + + virtual QWidget * paramWidget(); + + public slots: + void connectionsChanged(); + + void newConnection(); +}; #endif // QGSGDALDATAITEMS_H diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index 07d7f1dd9e9..b9dbaf0b7cf 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -2017,3 +2017,35 @@ QGISEXTERN void buildSupportedRasterFileFilter( QString & theFileFiltersString ) QStringList wildcards; buildSupportedRasterFileFilterAndExtensions( theFileFiltersString, exts, wildcards ); } + +QMap QgsGdalProvider::supportedMimes() +{ + QMap 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; +} diff --git a/src/providers/gdal/qgsgdalprovider.h b/src/providers/gdal/qgsgdalprovider.h index 70063e7083b..ec94e688804 100644 --- a/src/providers/gdal/qgsgdalprovider.h +++ b/src/providers/gdal/qgsgdalprovider.h @@ -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 supportedMimes(); + signals: void statusChanged( QString ); diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp index 6d55bd9eb68..9a7114f046f 100644 --- a/src/providers/gdal/qgswcscapabilities.cpp +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -118,6 +118,11 @@ QString QgsWcsCapabilities::prepareUri( QString uri ) return uri; } +QgsWcsCapabilitiesProperty QgsWcsCapabilities::capabilities() +{ + return mCapabilities; +} + bool QgsWcsCapabilities::supportedCoverages( QVector &coverageSummary ) { QgsDebugMsg( "Entering." ); diff --git a/src/providers/gdal/qgswcscapabilities.h b/src/providers/gdal/qgswcscapabilities.h index 05466b66698..60f1e92cf16 100644 --- a/src/providers/gdal/qgswcscapabilities.h +++ b/src/providers/gdal/qgswcscapabilities.h @@ -146,6 +146,8 @@ class QgsWcsCapabilities : public QObject void setUri( QgsDataSourceURI const &theUri ); + QgsWcsCapabilitiesProperty capabilities(); + /** * \brief Returns a list of the supported layers of the WCS server * diff --git a/src/providers/gdal/qgswcssourceselect.cpp b/src/providers/gdal/qgswcssourceselect.cpp index e1e9fbe0f2f..2f243a60bab 100644 --- a/src/providers/gdal/qgswcssourceselect.cpp +++ b/src/providers/gdal/qgswcssourceselect.cpp @@ -19,6 +19,7 @@ #include "qgis.h" #include "qgslogger.h" +#include "qgsgdalprovider.h" #include "qgswcssourceselect.h" #include "qgswcscapabilities.h" #include "qgsnumericsortlistviewitem.h" @@ -169,33 +170,14 @@ QList QgsWCSSourceSelect::providerFormats() { QgsDebugMsg( "entered" ); QList formats; - GDALAllRegister(); - QgsDebugMsg( QString( "GDAL drivers cont %1" ).arg( GDALGetDriverCount() ) ); - for ( int i = 0; i < GDALGetDriverCount(); ++i ) + QMap mimes = QgsGdalProvider::supportedMimes(); + foreach( QString mime, mimes.keys() ) { - GDALDriverH driver = GDALGetDriver( i ); - Q_CHECK_PTR( driver ); + QgsOWSSupportedFormat format = { mime, mimes.value( mime ) }; - 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; - - QgsOWSSupportedFormat format = { mimeType, desc }; - - QgsDebugMsg( "add GDAL format " + mimeType + " " + desc ); - - if ( mimeType == "image/tiff" ) + // prefer tiff + if ( mime == "image/tiff" ) { formats.prepend( format ); } From bcd9bd74d216391bb4bce561553b3f375f409bfc Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Mon, 30 Apr 2012 12:42:20 +0200 Subject: [PATCH 13/19] WFS adapted to QgsOWSConnection, remaining functionality from QgsWFSConnection moved to QgsWFSCapabilities --- src/providers/wfs/CMakeLists.txt | 4 +- ...sconnection.cpp => qgswfscapabilities.cpp} | 90 +++++++++---------- ...gswfsconnection.h => qgswfscapabilities.h} | 30 ++++--- src/providers/wfs/qgswfsdataitems.cpp | 37 ++++---- src/providers/wfs/qgswfsdataitems.h | 6 +- src/providers/wfs/qgswfssourceselect.cpp | 60 +++++++------ src/providers/wfs/qgswfssourceselect.h | 4 +- 7 files changed, 120 insertions(+), 111 deletions(-) rename src/providers/wfs/{qgswfsconnection.cpp => qgswfscapabilities.cpp} (79%) rename src/providers/wfs/{qgswfsconnection.h => qgswfscapabilities.h} (77%) diff --git a/src/providers/wfs/CMakeLists.txt b/src/providers/wfs/CMakeLists.txt index 1119228752f..70ddaee8f35 100644 --- a/src/providers/wfs/CMakeLists.txt +++ b/src/providers/wfs/CMakeLists.txt @@ -4,7 +4,7 @@ SET(WFS_SRCS qgswfsprovider.cpp - qgswfsconnection.cpp + qgswfscapabilities.cpp qgswfsdataitems.cpp qgswfsdata.cpp qgswfssourceselect.cpp @@ -13,7 +13,7 @@ SET(WFS_SRCS SET (WFS_MOC_HDRS qgswfsdata.h - qgswfsconnection.h + qgswfscapabilities.h qgswfsdataitems.h qgswfsprovider.h qgswfssourceselect.h diff --git a/src/providers/wfs/qgswfsconnection.cpp b/src/providers/wfs/qgswfscapabilities.cpp similarity index 79% rename from src/providers/wfs/qgswfsconnection.cpp rename to src/providers/wfs/qgswfscapabilities.cpp index 8067ace8be2..95d8a9d332b 100644 --- a/src/providers/wfs/qgswfsconnection.cpp +++ b/src/providers/wfs/qgswfscapabilities.cpp @@ -1,4 +1,4 @@ -#include "qgswfsconnection.h" +#include "qgswfscapabilities.h" #include "qgsexpression.h" #include "qgslogger.h" #include "qgsnetworkaccessmanager.h" @@ -11,18 +11,25 @@ static const QString WFS_NAMESPACE = "http://www.opengis.net/wfs"; -QgsWFSConnection::QgsWFSConnection( QString connName, QObject *parent ) : - QObject( parent ), - mConnName( connName ), +QgsWFSCapabilities::QgsWFSCapabilities( QString theUri ) : + //QObject( parent ), + //mConnName( connName ), mCapabilitiesReply( 0 ), - mErrorCode( QgsWFSConnection::NoError ) + mErrorCode( QgsWFSCapabilities::NoError ) { + mUri.setEncodedUri( theUri ), + QgsDebugMsg ( "theUri = " + theUri ); + mBaseUrl = prepareUri ( mUri.param("url") ); + + QgsDebugMsg ( "mBaseUrl = " + mBaseUrl ); + //find out the server URL + /* QSettings settings; QString key = "/Qgis/connections-wfs/" + mConnName + "/url"; mUri = settings.value( key ).toString(); QgsDebugMsg( QString( "url is: %1" ).arg( mUri ) ); - + //make a GetCapabilities request //modify mUri to add '?' or '&' at the end if it is not already there if ( !( mUri.contains( "?" ) ) ) @@ -33,19 +40,34 @@ QgsWFSConnection::QgsWFSConnection( QString connName, QObject *parent ) : { mUri.append( "&" ); } + */ } -QString QgsWFSConnection::uriGetCapabilities() const +QString QgsWFSCapabilities::prepareUri( QString uri ) { - return mUri + "SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"; + if ( !uri.contains( "?" ) ) + { + uri.append( "?" ); + } + else if ( uri.right( 1 ) != "?" && uri.right( 1 ) != "&" ) + { + uri.append( "&" ); + } + + return uri; } -QString QgsWFSConnection::uriDescribeFeatureType( const QString& typeName ) const +QString QgsWFSCapabilities::uriGetCapabilities() const { - return mUri + "SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=" + typeName; + return mBaseUrl + "SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"; } -QString QgsWFSConnection::uriGetFeature( QString typeName, QString crsString, QString filter, QgsRectangle bBox ) const +QString QgsWFSCapabilities::uriDescribeFeatureType( const QString& typeName ) const +{ + return mBaseUrl + "SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=" + typeName; +} + +QString QgsWFSCapabilities::uriGetFeature( QString typeName, QString crsString, QString filter, QgsRectangle bBox ) const { //get CRS if ( !crsString.isEmpty() ) @@ -89,11 +111,7 @@ QString QgsWFSConnection::uriGetFeature( QString typeName, QString crsString, QS .arg( bBox.yMaximum(), 0, 'f' ); } - QString uri = mUri; - if ( !( uri.contains( "?" ) ) ) - { - uri.append( "?" ); - } + QString uri = mBaseUrl; //add a wfs layer to the map uri += "SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=" + typeName + crsString + bBoxString + filterString; @@ -102,9 +120,9 @@ QString QgsWFSConnection::uriGetFeature( QString typeName, QString crsString, QS } -void QgsWFSConnection::requestCapabilities() +void QgsWFSCapabilities::requestCapabilities() { - mErrorCode = QgsWFSConnection::NoError; + mErrorCode = QgsWFSCapabilities::NoError; mErrorMessage.clear(); QNetworkRequest request( uriGetCapabilities() ); @@ -113,12 +131,12 @@ void QgsWFSConnection::requestCapabilities() connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) ); } -void QgsWFSConnection::capabilitiesReplyFinished() +void QgsWFSCapabilities::capabilitiesReplyFinished() { // handle network errors if ( mCapabilitiesReply->error() != QNetworkReply::NoError ) { - mErrorCode = QgsWFSConnection::NetworkError; + mErrorCode = QgsWFSCapabilities::NetworkError; mErrorMessage = mCapabilitiesReply->errorString(); emit gotCapabilities(); return; @@ -149,7 +167,7 @@ void QgsWFSConnection::capabilitiesReplyFinished() QDomDocument capabilitiesDocument; if ( !capabilitiesDocument.setContent( buffer, true, &capabilitiesDocError ) ) { - mErrorCode = QgsWFSConnection::XmlError; + mErrorCode = QgsWFSCapabilities::XmlError; mErrorMessage = capabilitiesDocError; emit gotCapabilities(); return; @@ -163,7 +181,7 @@ void QgsWFSConnection::capabilitiesReplyFinished() QDomNode ex = doc.firstChild(); QString exc = ex.toElement().attribute( "exceptionCode", "Exception" ); QDomElement ext = ex.firstChild().toElement(); - mErrorCode = QgsWFSConnection::ServerExceptionError; + mErrorCode = QgsWFSCapabilities::ServerExceptionError; mErrorMessage = exc + ": " + ext.firstChild().nodeValue(); emit gotCapabilities(); return; @@ -226,31 +244,3 @@ void QgsWFSConnection::capabilitiesReplyFinished() emit gotCapabilities(); } - - - -QStringList QgsWFSConnection::connectionList() -{ - QSettings settings; - settings.beginGroup( "/Qgis/connections-wfs" ); - return settings.childGroups(); -} - -QString QgsWFSConnection::selectedConnection() -{ - QSettings settings; - return settings.value( "/Qgis/connections-wfs/selected" ).toString(); -} - -void QgsWFSConnection::setSelectedConnection( QString name ) -{ - QSettings settings; - settings.setValue( "/Qgis/connections-wfs/selected", name ); -} - -void QgsWFSConnection::deleteConnection( QString name ) -{ - QSettings settings; - settings.remove( "/Qgis/connections-wfs/" + name ); - settings.remove( "/Qgis/WFS/" + name ); -} diff --git a/src/providers/wfs/qgswfsconnection.h b/src/providers/wfs/qgswfscapabilities.h similarity index 77% rename from src/providers/wfs/qgswfsconnection.h rename to src/providers/wfs/qgswfscapabilities.h index 07624de9c69..d004772ec74 100644 --- a/src/providers/wfs/qgswfsconnection.h +++ b/src/providers/wfs/qgswfscapabilities.h @@ -1,27 +1,25 @@ -#ifndef QGSWFSCONNECTION_H -#define QGSWFSCONNECTION_H +#ifndef QGSWFSCAPABILITIES_H +#define QGSWFSCAPABILITIES_H #include #include "qgsrectangle.h" +#include "qgsdatasourceuri.h" class QNetworkReply; -class QgsWFSConnection : public QObject +class QgsWFSCapabilities : public QObject { Q_OBJECT public: - explicit QgsWFSConnection( QString connName, QObject *parent = 0 ); + //explicit QgsWFSCapabilities( QString connName, QObject *parent = 0 ); + QgsWFSCapabilities( QString theUri ); - static QStringList connectionList(); - - static void deleteConnection( QString name ); - - static QString selectedConnection(); - static void setSelectedConnection( QString name ); + //! Append ? or & if necessary + QString prepareUri( QString uri ); //! base service URI - QString uri() const { return mUri; } + QString uri() const { return mBaseUrl; } //! URI to get capabilities QString uriGetCapabilities() const; //! URI to get schema of wfs layer @@ -67,8 +65,12 @@ class QgsWFSConnection : public QObject void capabilitiesReplyFinished(); protected: - QString mConnName; - QString mUri; + //QString mConnName; + //QString mUri; + + QgsDataSourceURI mUri; + + QString mBaseUrl; QNetworkReply *mCapabilitiesReply; GetCapabilities mCaps; @@ -76,4 +78,4 @@ class QgsWFSConnection : public QObject QString mErrorMessage; }; -#endif // QGSWFSCONNECTION_H +#endif // QGSWFSCAPABILITIES_H diff --git a/src/providers/wfs/qgswfsdataitems.cpp b/src/providers/wfs/qgswfsdataitems.cpp index 3378b826224..23e7a7841ef 100644 --- a/src/providers/wfs/qgswfsdataitems.cpp +++ b/src/providers/wfs/qgswfsdataitems.cpp @@ -1,7 +1,8 @@ #include "qgswfsdataitems.h" #include "qgswfsprovider.h" -#include "qgswfsconnection.h" +#include "qgsowsconnection.h" +#include "qgswfscapabilities.h" #include "qgswfssourceselect.h" #include "qgsnewhttpconnection.h" @@ -10,10 +11,10 @@ #include -QgsWFSLayerItem::QgsWFSLayerItem( QgsDataItem* parent, QString connName, QString name, QString title ) +QgsWFSLayerItem::QgsWFSLayerItem( QgsDataItem* parent, QString name, QgsDataSourceURI uri, QString featureType, QString title ) : QgsLayerItem( parent, title, parent->path() + "/" + name, QString(), QgsLayerItem::Vector, "WFS" ) { - mUri = QgsWFSConnection( connName ).uriGetFeature( name ); + mUri = QgsWFSCapabilities( uri.encodedUri() ).uriGetFeature( featureType ); mPopulated = true; } @@ -24,7 +25,7 @@ QgsWFSLayerItem::~QgsWFSLayerItem() //// QgsWFSConnectionItem::QgsWFSConnectionItem( QgsDataItem* parent, QString name, QString path ) - : QgsDataCollectionItem( parent, name, path ), mName( name ), mConn( NULL ) + : QgsDataCollectionItem( parent, name, path ), mName( name ), mCapabilities( NULL ) { mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) ); } @@ -36,10 +37,15 @@ QgsWFSConnectionItem::~QgsWFSConnectionItem() QVector QgsWFSConnectionItem::createChildren() { mGotCapabilities = false; - mConn = new QgsWFSConnection( mName, this ); - connect( mConn, SIGNAL( gotCapabilities() ), this, SLOT( gotCapabilities() ) ); - mConn->requestCapabilities(); + QgsOWSConnection connection( "WFS", mName ); + QgsDataSourceURI uri = connection.uri(); + QString encodedUri = uri.encodedUri(); + + mCapabilities = new QgsWFSCapabilities( encodedUri ); + connect( mCapabilities, SIGNAL( gotCapabilities() ), this, SLOT( gotCapabilities() ) ); + + mCapabilities->requestCapabilities(); while ( !mGotCapabilities ) { @@ -47,12 +53,13 @@ QVector QgsWFSConnectionItem::createChildren() } QVector layers; - if ( mConn->errorCode() == QgsWFSConnection::NoError ) + if ( mCapabilities->errorCode() == QgsWFSCapabilities::NoError ) { - QgsWFSConnection::GetCapabilities caps = mConn->capabilities(); - foreach( const QgsWFSConnection::FeatureType& featureType, caps.featureTypes ) + QgsWFSCapabilities::GetCapabilities caps = mCapabilities->capabilities(); + foreach( const QgsWFSCapabilities::FeatureType& featureType, caps.featureTypes ) { - QgsWFSLayerItem* layer = new QgsWFSLayerItem( this, mName, featureType.name, featureType.title ); + //QgsWFSLayerItem* layer = new QgsWFSLayerItem( this, mName, featureType.name, featureType.title ); + QgsWFSLayerItem* layer = new QgsWFSLayerItem( this, mName, uri, featureType.name, featureType.title ); layers.append( layer ); } } @@ -61,8 +68,8 @@ QVector QgsWFSConnectionItem::createChildren() layers.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); } - mConn->deleteLater(); - mConn = NULL; + mCapabilities->deleteLater(); + mCapabilities = NULL; return layers; } @@ -101,7 +108,7 @@ void QgsWFSConnectionItem::editConnection() void QgsWFSConnectionItem::deleteConnection() { - QgsWFSConnection::deleteConnection( mName ); + QgsOWSConnection::deleteConnection( "WFS", mName ); // the parent should be updated mParent->refresh(); } @@ -127,7 +134,7 @@ QVector QgsWFSRootItem::createChildren() { QVector connections; - foreach( QString connName, QgsWFSConnection::connectionList() ) + foreach( QString connName, QgsOWSConnection::connectionList( "WFS" ) ) { QgsDataItem * conn = new QgsWFSConnectionItem( this, connName, mPath + "/" + connName ); connections.append( conn ); diff --git a/src/providers/wfs/qgswfsdataitems.h b/src/providers/wfs/qgswfsdataitems.h index 3f171c6749e..968b72426fe 100644 --- a/src/providers/wfs/qgswfsdataitems.h +++ b/src/providers/wfs/qgswfsdataitems.h @@ -2,6 +2,8 @@ #define QGSWFSDATAITEMS_H #include "qgsdataitem.h" +#include "qgsdatasourceuri.h" +#include "qgswfscapabilities.h" class QgsWFSRootItem : public QgsDataCollectionItem { @@ -45,7 +47,7 @@ class QgsWFSConnectionItem : public QgsDataCollectionItem private: QString mName; - QgsWFSConnection* mConn; + QgsWFSCapabilities* mCapabilities; bool mGotCapabilities; }; @@ -53,7 +55,7 @@ class QgsWFSConnectionItem : public QgsDataCollectionItem class QgsWFSLayerItem : public QgsLayerItem { public: - QgsWFSLayerItem( QgsDataItem* parent, QString connName, QString name, QString title ); + QgsWFSLayerItem( QgsDataItem* parent, QString name, QgsDataSourceURI uri, QString featureType, QString title ); ~QgsWFSLayerItem(); }; diff --git a/src/providers/wfs/qgswfssourceselect.cpp b/src/providers/wfs/qgswfssourceselect.cpp index b0fabb55e75..9eb154dd97b 100644 --- a/src/providers/wfs/qgswfssourceselect.cpp +++ b/src/providers/wfs/qgswfssourceselect.cpp @@ -16,7 +16,8 @@ ***************************************************************************/ #include "qgswfssourceselect.h" -#include "qgswfsconnection.h" +#include "qgsowsconnection.h" +#include "qgswfscapabilities.h" #include "qgswfsprovider.h" #include "qgsnewhttpconnection.h" #include "qgsgenericprojectionselector.h" @@ -38,7 +39,7 @@ QgsWFSSourceSelect::QgsWFSSourceSelect( QWidget* parent, Qt::WFlags fl, bool embeddedMode ) : QDialog( parent, fl ) - , mConn( NULL ) + , mCapabilities( NULL ) { setupUi( this ); @@ -75,12 +76,12 @@ QgsWFSSourceSelect::~QgsWFSSourceSelect() settings.setValue( "/Windows/WFSSourceSelect/geometry", saveGeometry() ); delete mProjectionSelector; - delete mConn; + delete mCapabilities; } void QgsWFSSourceSelect::populateConnectionList() { - QStringList keys = QgsWFSConnection::connectionList(); + QStringList keys = QgsOWSConnection::connectionList( "WFS" ); QStringList::Iterator it = keys.begin(); cmbConnections->clear(); @@ -107,16 +108,17 @@ void QgsWFSSourceSelect::populateConnectionList() } //set last used connection - QString selectedConnection = QgsWFSConnection::selectedConnection(); + QString selectedConnection = QgsOWSConnection::selectedConnection( "WFS" ); int index = cmbConnections->findText( selectedConnection ); if ( index != -1 ) { cmbConnections->setCurrentIndex( index ); } - delete mConn; - mConn = new QgsWFSConnection( cmbConnections->currentText() ); - connect( mConn, SIGNAL( gotCapabilities() ), this, SLOT( capabilitiesReplyFinished() ) ); + QgsOWSConnection connection( "WFS", cmbConnections->currentText() ); + delete mCapabilities; + mCapabilities = new QgsWFSCapabilities( connection.uri().encodedUri() ); + connect( mCapabilities, SIGNAL( gotCapabilities() ), this, SLOT( capabilitiesReplyFinished() ) ); } QString QgsWFSSourceSelect::getPreferredCrs( const QSet& crsSet ) const @@ -155,30 +157,30 @@ void QgsWFSSourceSelect::capabilitiesReplyFinished() { btnConnect->setEnabled( true ); - if ( !mConn ) + if ( !mCapabilities ) return; - QgsWFSConnection::ErrorCode err = mConn->errorCode(); - if ( err != QgsWFSConnection::NoError ) + QgsWFSCapabilities::ErrorCode err = mCapabilities->errorCode(); + if ( err != QgsWFSCapabilities::NoError ) { QString title; switch ( err ) { - case QgsWFSConnection::NetworkError: title = tr( "Network Error" ); break; - case QgsWFSConnection::XmlError: title = tr( "Capabilities document is not valid" ); break; - case QgsWFSConnection::ServerExceptionError: title = tr( "Server Exception" ); break; + case QgsWFSCapabilities::NetworkError: title = tr( "Network Error" ); break; + case QgsWFSCapabilities::XmlError: title = tr( "Capabilities document is not valid" ); break; + case QgsWFSCapabilities::ServerExceptionError: title = tr( "Server Exception" ); break; default: tr( "Error" ); break; } // handle errors - QMessageBox::critical( 0, title, mConn->errorMessage() ); + QMessageBox::critical( 0, title, mCapabilities->errorMessage() ); btnAdd->setEnabled( false ); return; } - QgsWFSConnection::GetCapabilities caps = mConn->capabilities(); + QgsWFSCapabilities::GetCapabilities caps = mCapabilities->capabilities(); mAvailableCRS.clear(); - foreach( QgsWFSConnection::FeatureType featureType, caps.featureTypes ) + foreach( QgsWFSCapabilities::FeatureType featureType, caps.featureTypes ) { // insert the typenames, titles and abstracts into the tree view QTreeWidgetItem* newItem = new QTreeWidgetItem(); @@ -242,7 +244,7 @@ void QgsWFSSourceSelect::deleteEntryOfServerList() QMessageBox::StandardButton result = QMessageBox::information( this, tr( "Confirm Delete" ), msg, QMessageBox::Ok | QMessageBox::Cancel ); if ( result == QMessageBox::Ok ) { - QgsWFSConnection::deleteConnection( cmbConnections->currentText() ); + QgsOWSConnection::deleteConnection( "WFS", cmbConnections->currentText() ); cmbConnections->removeItem( cmbConnections->currentIndex() ); emit connectionsChanged(); } @@ -253,9 +255,9 @@ void QgsWFSSourceSelect::connectToServer() btnConnect->setEnabled( false ); treeWidget->clear(); - if ( mConn ) + if ( mCapabilities ) { - mConn->requestCapabilities(); + mCapabilities->requestCapabilities(); } } @@ -271,7 +273,10 @@ void QgsWFSSourceSelect::addLayer() QList selectedItems = treeWidget->selectedItems(); QList::const_iterator sIt = selectedItems.constBegin(); - QgsWFSConnection conn( cmbConnections->currentText() ); + + QgsOWSConnection connection( "WFS", cmbConnections->currentText() ); + QgsWFSCapabilities conn ( connection.uri().encodedUri() ); + QString pCrsString( labelCoordRefSys->text() ); QgsCoordinateReferenceSystem pCrs( pCrsString ); //prepare canvas extent info for layers with "cache features" option not set @@ -375,11 +380,13 @@ void QgsWFSSourceSelect::changeCRSFilter() void QgsWFSSourceSelect::on_cmbConnections_activated( int index ) { Q_UNUSED( index ); - QgsWFSConnection::setSelectedConnection( cmbConnections->currentText() ); + QgsOWSConnection::setSelectedConnection( "WFS", cmbConnections->currentText() ); - delete mConn; - mConn = new QgsWFSConnection( cmbConnections->currentText() ); - connect( mConn, SIGNAL( gotCapabilities() ), this, SLOT( capabilitiesReplyFinished() ) ); + QgsOWSConnection connection( "WFS", cmbConnections->currentText() ); + + delete mCapabilities; + mCapabilities = new QgsWFSCapabilities( connection.uri().encodedUri() ); + connect( mCapabilities, SIGNAL( gotCapabilities() ), this, SLOT( capabilitiesReplyFinished() ) ); } void QgsWFSSourceSelect::on_btnSave_clicked() @@ -409,7 +416,8 @@ void QgsWFSSourceSelect::on_treeWidget_itemDoubleClicked( QTreeWidgetItem* item, { //get available fields for wfs layer QgsWFSProvider p( "" ); //bypasses most provider instantiation logic - QgsWFSConnection conn( cmbConnections->currentText() ); + QgsOWSConnection connection( "WFS", cmbConnections->currentText() ); + QgsWFSCapabilities conn ( connection.uri().encodedUri() ); QString uri = conn.uriDescribeFeatureType( item->text( 1 ) ); QgsFieldMap fields; diff --git a/src/providers/wfs/qgswfssourceselect.h b/src/providers/wfs/qgswfssourceselect.h index 8342f3d3cff..cdac0b605af 100644 --- a/src/providers/wfs/qgswfssourceselect.h +++ b/src/providers/wfs/qgswfssourceselect.h @@ -22,7 +22,7 @@ #include "qgscontexthelp.h" class QgsGenericProjectionSelector; -class QgsWFSConnection; +class QgsWFSCapabilities; class QgsWFSSourceSelect: public QDialog, private Ui::QgsWFSSourceSelectBase { @@ -45,7 +45,7 @@ class QgsWFSSourceSelect: public QDialog, private Ui::QgsWFSSourceSelectBase stores the CRS for the typename in the form 'EPSG:XXXX'*/ std::map > mAvailableCRS; QAbstractButton* btnAdd; - QgsWFSConnection* mConn; + QgsWFSCapabilities* mCapabilities; QString mUri; // data source URI void populateConnectionList(); From ff8b451051a4c53c388fa30b38a92e50bd68b571 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Tue, 1 May 2012 14:09:44 +0200 Subject: [PATCH 14/19] new icons for vector layer and OWS data source --- images/images.qrc | 4 + images/themes/default/mIconOws.png | Bin 0 -> 2867 bytes images/themes/default/mIconVectorLayer.png | Bin 0 -> 971 bytes images/themes/gis/mIconOws.png | Bin 0 -> 1045 bytes images/themes/gis/mIconOws.svg | 675 +++++++++++++++++++++ images/themes/gis/mIconVectorLayer.png | Bin 0 -> 709 bytes images/themes/gis/mIconVectorLayer.svg | 237 ++++++++ 7 files changed, 916 insertions(+) create mode 100644 images/themes/default/mIconOws.png create mode 100644 images/themes/default/mIconVectorLayer.png create mode 100644 images/themes/gis/mIconOws.png create mode 100644 images/themes/gis/mIconOws.svg create mode 100644 images/themes/gis/mIconVectorLayer.png create mode 100644 images/themes/gis/mIconVectorLayer.svg diff --git a/images/images.qrc b/images/images.qrc index 23c8f21c5ce..082c943c9bb 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -172,6 +172,7 @@ themes/default/mIconMssql.png themes/default/mIconNext.png themes/default/mIconNoPyramid.png + themes/default/mIconOws.png themes/default/mIconPointLayer.png themes/default/mIconPolygonLayer.png themes/default/mIconPostgis.png @@ -189,6 +190,7 @@ themes/default/mIconSymbology.png themes/default/mIconTableLayer.png themes/default/mIconUnknownLayerType.png + themes/default/mIconVectorLayer.png themes/default/mIconWaitingForLayerType.png themes/default/mIconWfs.png themes/default/mIconWcs.png @@ -348,6 +350,7 @@ themes/gis/mIconPointLayer.png themes/gis/mIconPolygonLayer.png themes/gis/mIconTableLayer.png + themes/gis/mIconVectorLayer.png themes/gis/plugins/coordinate_capture/coordinate_capture.png themes/gis/plugins/copyright_label.png themes/gis/plugins/delimited_text.png @@ -372,6 +375,7 @@ themes/gis/mIconWcs.png themes/gis/mIconWms.png themes/gis/mIconWfs.png + themes/gis/mIconOws.png themes/gis/mIconSpatialite.png themes/gis/mIconRaster.png themes/gis/mIconPostgis.png diff --git a/images/themes/default/mIconOws.png b/images/themes/default/mIconOws.png new file mode 100644 index 0000000000000000000000000000000000000000..071035c95c8878d98c7b03d8adb77dff2eff51a2 GIT binary patch literal 2867 zcmV-33(WM1P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00VXa00VXbebs`@00007bV*G`2iyc4 z4*&r=JWsd)01C57L_t(o!;P1Da9!1X$3N%X``)|nzC~}*lk_AD$&xo&wrqL9sTT~G z6tEo}yCei^Qb{b+WYmqsb%$+G*11c%U?4FvM+Qw$#)Zyu=IGcwZzv zNzdAz^!DX0r+*0S2;&K7=H7emIp?1HJKx{;oZt5+_{62T?vHN%Y_E0arYG$BhOH=t zrU|4F2&Di}fLD_zet!S5JA@EJpJZ0?`v&x`czE5yMO_=0bvAdcY1ZR~?!~QRc-kD> z=H35N~06lj*C#rl~P3WLfkv6F~Xw8&{Qs8 z?5LDWow_D}qkE0vPlSMwH#M%^uxjJY>lXk0AH090rL{eVfBU`4h((Z^6xFIlCX*)= zkFfW|AU}NWO>|8nrNnkzP>Qc?U$0gzY7^C(MSCKE->W_8@f!d5`w<9iTD9%&b@#34 znfJNdg0-fepFB&xZY$^0<7gISrV31D3&bKpLeVg)P{3E1 zL!?Hg*mlcegb=u{`jb+r#Kp1Vj~BHiN*`;$?B$Qu1w-Z+BC+tjhQ~|<=CxqeMG;du zOsgUskA@4>Y(>phR4-iQ=H36v{LyoS<~+#4x;U=Tcy(Za_b;SHYch%^C7KXOAr>mh zA8JB8^|1(qyB`U9!=ZJNSZIqQ^n?gV)t?%nrDh2{UZTkaPBetjG)&WvQVMXrh!-RolT;QrM20tl94T*WXQ@ZwUK~J+tebD+V+* z*LP}~_O#s7=vvD#+iJ9h@-wcYp*?neRHSOa@~O`IPskgvMb#;2&A z>to9;J*-)f#OD>lvTT%6xJu}*QZa;xjO5b++R5nvfuOmz;;6gwwVa`p!jhUQT1re5 zYD{+ZkT~}~-sA5Q{{FX-=`^xb#P$0Tr4oah$-XfQyTK(K^y4@Vg;W}Mw22YF;#9GU zFH(onG(sLJ=hX+yNYL+ftRW923>_d;7wE1bdN1dzC|6-gO-xp7`o|0OubNBC-Cw}B z`&SshJ%EB~R@)8$r-O~0ZfFA`P)Z@C1h3@z*WW|AEQNPfa{j`oeSpd~^w92VZj5KHDHIX9G1xl+{z&~IJd68_SrdE)A!DEP$- z!#o~ZdF9ps!I&r*z{Nfvcrb+SjO{-@Mga9ExN?O_sP981N9*7`> zKnOvnCV44U!8gaoPMY)wbjrFSnXVCY1qWId@E=|4Ih^dEshnrgM2cDE9G-B1#T!=9 z91jA5n&Z+pmN&8$`^4Kjf3{biyjOc$lzZrZ3S-S?COA%jI0vdF#;5f7_#V z-LbvBSl+i*YpYT)N)(I|MWcirsgfD1vDTc0lnN;ong;Efm!qEZR5eMUCRsUZ(O7WU zduxmr|Mhtu|MDX&?P#LU6W~CsjjS1Be*bAka#en52gyYfSS|yauKn-6|9a-2R6V!9 zI5FtDuB)yIjAs+W43+aU+Ij*B)}>nr`3s~IRZhh;8Y(WE`zl0x{e1sBe@i^*WY^yWx`v?({5~I51VY!-hT$0lkVnTVr)p}}Sh?n0V}Pg8<>l&`YuX=w~P0YTQ2XKEYCnfsT1<@`kxYg9cuor_Ykw zFo5KrHs`hZ8xM{g5=5sW#HXUfCS%lRW7JQ@IZ?}yt++V0e&v#`m;3D%WKPcEKyD$= zCYxz22s+L-;FBx();Io=!DEMMd2R=7yLQsodm{%o+(jT6CmJ#^4Dadwf_>>qIPToI zegB!i{@La)-nUeQg2s&1x~t%&9iwb-ns-Hb0`x}P`1F{E7n{~I?4HGUW(VcaVrnhx zG5u?K{j*zH*x5y~zMi+f^cYU8RfG&3q^5)}jz4>M_uw=Fz<}fXmD$?W_u8?sYv7hr zkPc>XJ~$kM6BhC8D7KI^m2%v3 z{vh8tw3ER|l0R!~=j$)-5T@Z3hR=)8^}aJX>!)vzmItm;M5&H7|6cv|p}*OExQebx zgt&^g0?wHwTzhne8vy*i8a>4Uq;k3M{Qog&7@Uen_-Xe-{DCNH_+4Io>U*qw^s8Cn zh_`obZr^oXRXlgjywqPjaNjJySG&d)maU*B@ku$O-OOfLvhN*y<5LuT0WzT|$Gex1 zZBHPjLOCu+f4dK>_tri3P4_GGJmn4(Tytn&>*4MxL#6JMJ>l$F&_Sw2{@GA>C zW()B#8H1}7I08*vjhy2m%=zRTWYjh70bpM*FBm>@ z^4##O2472igL&20;=`Nb)QK9)&Da$p2*4*4B?PW=d8MkDh<&J#1g;P$BuWS>W@A8j z`~OGPN*k`5m<*?fev-~Ke*1yj=4%RZ&1%vkd3uW>n*G6#uxPpxvoidZr9NQ@ri^X@&o=RmVC$AFjqonehFH^}s{r?U9x6PYa Rj_CjZ002ovPDHLkV1mD4q?!N# literal 0 HcmV?d00001 diff --git a/images/themes/default/mIconVectorLayer.png b/images/themes/default/mIconVectorLayer.png new file mode 100644 index 0000000000000000000000000000000000000000..34139c7e1ad2636a564c725278744500ae0906b9 GIT binary patch literal 971 zcmV;+12p`JP)@~8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H114v0kK~z|U#gq0|Yp-5f%5z(Rq zg;bHcaUm{**5X#P5D`BX3a*T}GD>!W=)#SN2!a+{HASLUH!Wz3qNE>*eKA(;eaA(| zIGvdnCY^M0;BNl+y?cI~|GDSA;O_hvF^e|=$5Wo>=~1X5`3P_bc(_-|F8~1c0mp%< zwF1}-98P)qYpno&1$M+NR@VyPW#DSyrCtKy?n_Ii=VeMV-P@>_EoyA)X>US-iYa^aY=B z{5PEOLdD%FPwR?MJO~7rj{@T>Nq+v&c6ZZstxUO0lg)e4;%=Gd7{a=p0WE{53F1ka z3YkV)AZqbTnI2yafHDgJCV=mO$(Y5Q}mp1Ul0fcI}rec*x!a!JRyp*Sdz|+7_!2Q5X%;G+GzXkYVH2{{ps90rZw0JaGojpi?{rQ=S=`Jz&F6(z%Z}_8037f zOaO1DJS}uYQ0h&_NX+82Op7v2a1}Lo2jec8P65>hTY^k?%Jg3SkLnkhc6K$08bG!N z3!ljJHO6+CzLn|OWd_(bnZA(ev`ja24N$kJBGYR!d9=76h|5kl(?*$&)hqF$Ob^J^ zc66`o%4}eu(`RKGmgysz&em_utW3MR0=SqZQ2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4d1ziRI@L(hEiLSB1m*awKfog(47CPq_ zR2F5XXOu8FJ1aPrloVwqm4fu>24?`h?U<99ovM&gQc_^0ub&Jyt}HbnBy}7ANW(>lx_BHAn4XU|_27ba4#v=zKdZ-v4rd#IgBByQXbPwPNpK zG37~O>P}KnIVa&`FsouAXE-k>=f`sg=6>Y=d8EZ9?Xmk0uvnqMW1}C^qABVv1YmNw5`vdeocCrl$DirfBUCedB>%Ku@{Rq z0@#fAa=Hd;+ss;~IKOy7rq-<4vpZEhYj>@i9P}Y+XJtjjjzvFi|I*i)wO-MiF=Z2< z#?lE-k8$;{TD4*Gw|BcVZ>Y@lQ(=4X*zQ2wU!U|1d;dyv=idvvM4nUN{ad#^+kYQO=U1QquqfVM=XBHDt%7fRm>7gkclvIBux3h4 zsPnpIF?#Hwp=H<0uB8cXOMJt`$MxN!NQS*@6(fVr=|?>qmwvL}z0UlBoV(rh_Ej1Q zJqHaYsVzMhvGe(Q$&kyho`;sWSWh^alXTPL-v?m0zTdGzGC*U8Mo#L%ncRmoW6Y~x zE{F^ouI(@D9qz8;sLacIcc1at@#C$+ o@8g(c%=-P9s-6V9uKmT_DaO(F`E$#3U + + + + layer OGC Web service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + layer OGC Web service + 2012-04-30 + + + Robert Szczepanek + + + + + Robert Szczepanek + + + + + layer + OGC + web service + + + GIS icons 0.2 + + Generic icon for OGC Web service - OWS + (WMS,WFS,WCS) + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/themes/gis/mIconVectorLayer.png b/images/themes/gis/mIconVectorLayer.png new file mode 100644 index 0000000000000000000000000000000000000000..e33d518182e9ce949e64bddfd50a503cfe1961d1 GIT binary patch literal 709 zcmV;$0y_PPP)TkS{PO+1Y^yhppS{x zolFarkb&hzJ6@D2-UOQ$B?zMnH6rV>QH!V)ML{YkD*AxXNGhU>V3m$^p1objB$;PB z;x7ANo%cD<^Z&i?`@r)`LI?nkG_(X%S*}J=E=9W9ddQOGx^Ra07+3>f`P!)%xwIX>Fw!ytJbVJ67hJq%iAPe-X@WV$Gf#=&4I38 zSOAE0we`e)P8I!$#SS>VjrnH$r)Oq92Lr*VY_Zgj^mR%jeVvkQvD9}2JH}Cz%K%cc z2T8fS=UNcbzL8sPmZ$!^sI066VB4;7dc*ykIaP(K$SFl{#wK|D?i>Dw)2OOK zI2<Gn%IbY{*&7F;@xK@Al8fX7vQO9}H9DIfx`JdgZBrWOEl&McIBPzJBNRhfe@J z9DR;GcO6CBx0*7CG$#O1RfXCUhv~WVh+mU2!UIq69(S8I&j^6IhFh&xw5vDBx7*l~ zmz!Mx%-#KYzn{t2^pea?1Ipc{bYBZmURJtffSNf4oW%t=iwl-)4kk~q9Q_Am)Pg3b rn~KW@7|rvn0F35QHlQg_X14VgBHzI;{!71p00000NkvXXu0mjfvrI$l literal 0 HcmV?d00001 diff --git a/images/themes/gis/mIconVectorLayer.svg b/images/themes/gis/mIconVectorLayer.svg new file mode 100644 index 00000000000..29ca73d8bd2 --- /dev/null +++ b/images/themes/gis/mIconVectorLayer.svg @@ -0,0 +1,237 @@ + + + + + GIS icon theme 0.2 + + + + + + + + + + + + + + + + image/svg+xml + + GIS icon theme 0.2 + + + Robert Szczepanek + + + + + Robert Szczepanek + + + + + GIS icons + + + GIS icons + http://robert.szczepanek.pl/ + + + + + + + + + + + + + + + + + + + + + + + + + + From b6193dbb07ada75a2f0fd840093fc742a3bd602c Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Tue, 1 May 2012 14:15:32 +0200 Subject: [PATCH 15/19] OWS meta provider; represents all OWS services under single connection in browser --- src/core/qgsdataitem.cpp | 35 +++- src/core/qgsdataitem.h | 7 +- src/providers/CMakeLists.txt | 1 + src/providers/gdal/qgsgdaldataitems.cpp | 41 ++-- src/providers/gdal/qgsgdaldataitems.h | 2 - src/providers/ows/CMakeLists.txt | 26 +++ src/providers/ows/qgsowsdataitems.cpp | 239 ++++++++++++++++++++++++ src/providers/ows/qgsowsdataitems.h | 42 +++++ src/providers/ows/qgsowsprovider.cpp | 65 +++++++ src/providers/ows/qgsowsprovider.h | 66 +++++++ src/providers/wfs/qgswfsdataitems.cpp | 35 ++-- src/providers/wms/qgswmsdataitems.cpp | 55 ++++-- 12 files changed, 572 insertions(+), 42 deletions(-) create mode 100644 src/providers/ows/CMakeLists.txt create mode 100644 src/providers/ows/qgsowsdataitems.cpp create mode 100644 src/providers/ows/qgsowsdataitems.h create mode 100644 src/providers/ows/qgsowsprovider.cpp create mode 100644 src/providers/ows/qgsowsprovider.h diff --git a/src/core/qgsdataitem.cpp b/src/core/qgsdataitem.cpp index af94be5610c..6461026f086 100644 --- a/src/core/qgsdataitem.cpp +++ b/src/core/qgsdataitem.cpp @@ -134,10 +134,16 @@ const QIcon &QgsFavouritesItem::iconFavourites() } 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 ) @@ -215,6 +221,7 @@ bool QgsDataItem::hasChildren() void QgsDataItem::addChildItem( QgsDataItem * child, bool refresh ) { QgsDebugMsg( QString( "add child #%1 - %2" ).arg( mChildren.size() ).arg( child->mName ) ); + QgsDebugMsg( QString("child = 0x%0").arg((qlonglong)child,8,16,QLatin1Char('0')) ); int i; if ( type() == Directory ) @@ -264,6 +271,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 items, QgsDataItem * item ) { for ( int i = 0; i < items.size(); i++ ) @@ -368,8 +395,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; + } } //----------------------------------------------------------------------- diff --git a/src/core/qgsdataitem.h b/src/core/qgsdataitem.h index bba2943a9d4..8b84d922452 100644 --- a/src/core/qgsdataitem.h +++ b/src/core/qgsdataitem.h @@ -52,7 +52,7 @@ class CORE_EXPORT QgsDataItem : public QObject }; QgsDataItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path ); - virtual ~QgsDataItem() {} + virtual ~QgsDataItem(); bool hasChildren(); @@ -75,6 +75,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; } @@ -113,6 +117,7 @@ class CORE_EXPORT QgsDataItem : public QObject Type type() const { return mType; } QgsDataItem* parent() const { return mParent; } + void setParent( QgsDataItem* parent ) { mParent = parent; } QVector children() const { return mChildren; } QIcon icon() const { return mIcon; } QString name() const { return mName; } diff --git a/src/providers/CMakeLists.txt b/src/providers/CMakeLists.txt index b5ac3e34c3d..ade98473bdf 100644 --- a/src/providers/CMakeLists.txt +++ b/src/providers/CMakeLists.txt @@ -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) diff --git a/src/providers/gdal/qgsgdaldataitems.cpp b/src/providers/gdal/qgsgdaldataitems.cpp index a90822a748c..f572a420579 100644 --- a/src/providers/gdal/qgsgdaldataitems.cpp +++ b/src/providers/gdal/qgsgdaldataitems.cpp @@ -60,11 +60,12 @@ bool QgsGdalLayerItem::setCrs( QgsCoordinateReferenceSystem crs ) QgsWCSConnectionItem::QgsWCSConnectionItem( QgsDataItem* parent, QString name, QString path ) : QgsDataCollectionItem( parent, name, path ) { - mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) ); + mIcon = QIcon( getThemePixmap( "mIconWcs.png" ) ); } QgsWCSConnectionItem::~QgsWCSConnectionItem() { + QgsDebugMsg( "Entered"); } QVector QgsWCSConnectionItem::createChildren() @@ -72,16 +73,18 @@ QVector QgsWCSConnectionItem::createChildren() QgsDebugMsg( "Entered" ); QVector children; - QgsOWSConnection connection( "WCS", mName ); + QString encodedUri = mPath; + QgsDataSourceURI uri; + uri.setEncodedUri ( encodedUri ); + QgsDebugMsg( "encodedUri = " + encodedUri ); - QgsDataSourceURI uri = connection.uri(); - QgsDebugMsg( "uri = " + uri.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" ) ); + //children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); + // TODO: show the error without adding child return children; } @@ -105,9 +108,12 @@ bool QgsWCSConnectionItem::equal( const QgsDataItem *other ) return false; } const QgsWCSConnectionItem *o = dynamic_cast( other ); - //TODO - //return ( mPath == o->mPath && mName == o->mName && mConnInfo == o->mConnInfo ); - return false; + if ( !o ) + { + return false; + } + + return ( mPath == o->mPath && mName == o->mName ); } QList QgsWCSConnectionItem::actions() @@ -166,7 +172,8 @@ QgsWCSLayerItem::QgsWCSLayerItem( QgsDataItem* parent, QString name, QString pat if ( mChildren.size() == 0 ) { - mIcon = iconRaster(); + //mIcon = iconRaster(); + mIcon = QIcon( getThemePixmap( "mIconWcs.png" ) ); } mPopulated = true; } @@ -246,7 +253,11 @@ QVectorQgsWCSRootItem::createChildren() QVector connections; foreach( QString connName, QgsOWSConnection::connectionList( "WCS" ) ) { - QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, mPath + "/" + connName ); + //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; @@ -294,17 +305,25 @@ 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() ) { // 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 ); + } + QFileInfo info( thePath ); if ( info.isFile() ) { diff --git a/src/providers/gdal/qgsgdaldataitems.h b/src/providers/gdal/qgsgdaldataitems.h index 33f4c243900..fe6dee7f841 100644 --- a/src/providers/gdal/qgsgdaldataitems.h +++ b/src/providers/gdal/qgsgdaldataitems.h @@ -30,8 +30,6 @@ class QgsWCSConnectionItem : public QgsDataCollectionItem virtual QList actions(); QgsWcsCapabilities mCapabilities; - //QgsDataSourceURI mUri; - //QgsOWSConnection mConnection; QVector mLayerProperties; public slots: diff --git a/src/providers/ows/CMakeLists.txt b/src/providers/ows/CMakeLists.txt new file mode 100644 index 00000000000..e9e3e4d4054 --- /dev/null +++ b/src/providers/ows/CMakeLists.txt @@ -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}) diff --git a/src/providers/ows/qgsowsdataitems.cpp b/src/providers/ows/qgsowsdataitems.cpp new file mode 100644 index 00000000000..bcfce8f63fd --- /dev/null +++ b/src/providers/ows/qgsowsdataitems.cpp @@ -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 + +// --------------------------------------------------------------------------- +QgsOWSConnectionItem::QgsOWSConnectionItem( QgsDataItem* parent, QString name, QString path ) + : QgsDataCollectionItem( parent, name, path ) +{ + mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) ); +} + +QgsOWSConnectionItem::~QgsOWSConnectionItem() +{ +} + +QVector QgsOWSConnectionItem::createChildren() +{ + QgsDebugMsg( "Entered" ); + QVector children; + + QVector 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( other ); + return ( mPath == o->mPath && mName == o->mName ); +} + +QList QgsOWSConnectionItem::actions() +{ + QList 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() +{ +} + +QVectorQgsOWSRootItem::createChildren() +{ + QgsDebugMsg( "Entered" ); + QVector connections; + // Combine all WMS,WFS,WCS connections + QMap 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 QgsOWSRootItem::actions() +{ + QList 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; +} diff --git a/src/providers/ows/qgsowsdataitems.h b/src/providers/ows/qgsowsdataitems.h new file mode 100644 index 00000000000..4da9fe1c4c9 --- /dev/null +++ b/src/providers/ows/qgsowsdataitems.h @@ -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 createChildren(); + virtual bool equal( const QgsDataItem *other ); + + virtual QList actions(); + + public slots: + void editConnection(); + void deleteConnection(); +}; + +class QgsOWSRootItem : public QgsDataCollectionItem +{ + Q_OBJECT + public: + QgsOWSRootItem( QgsDataItem* parent, QString name, QString path ); + ~QgsOWSRootItem(); + + QVector createChildren(); + + virtual QList actions(); + + virtual QWidget * paramWidget(); + + public slots: + void connectionsChanged(); + + void newConnection(); +}; + +#endif // QGSOWSDATAITEMS_H diff --git a/src/providers/ows/qgsowsprovider.cpp b/src/providers/ows/qgsowsprovider.cpp new file mode 100644 index 00000000000..043708c2a0e --- /dev/null +++ b/src/providers/ows/qgsowsprovider.cpp @@ -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 + +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; +} + diff --git a/src/providers/ows/qgsowsprovider.h b/src/providers/ows/qgsowsprovider.h new file mode 100644 index 00000000000..241170434dd --- /dev/null +++ b/src/providers/ows/qgsowsprovider.h @@ -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 + +/** + + \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 diff --git a/src/providers/wfs/qgswfsdataitems.cpp b/src/providers/wfs/qgswfsdataitems.cpp index 23e7a7841ef..81bdbebeff6 100644 --- a/src/providers/wfs/qgswfsdataitems.cpp +++ b/src/providers/wfs/qgswfsdataitems.cpp @@ -1,12 +1,11 @@ -#include "qgswfsdataitems.h" - -#include "qgswfsprovider.h" +#include "qgslogger.h" +#include "qgsnewhttpconnection.h" #include "qgsowsconnection.h" #include "qgswfscapabilities.h" +#include "qgswfsdataitems.h" +#include "qgswfsprovider.h" #include "qgswfssourceselect.h" -#include "qgsnewhttpconnection.h" - #include #include @@ -16,6 +15,8 @@ QgsWFSLayerItem::QgsWFSLayerItem( QgsDataItem* parent, QString name, QgsDataSour { mUri = QgsWFSCapabilities( uri.encodedUri() ).uriGetFeature( featureType ); mPopulated = true; + //mIcon = QIcon( getThemePixmap( "mIconVectorLayer.png" ) ); + mIcon = QIcon( getThemePixmap( "mIconWfs.png" ) ); } QgsWFSLayerItem::~QgsWFSLayerItem() @@ -27,7 +28,7 @@ QgsWFSLayerItem::~QgsWFSLayerItem() QgsWFSConnectionItem::QgsWFSConnectionItem( QgsDataItem* parent, QString name, QString path ) : QgsDataCollectionItem( parent, name, path ), mName( name ), mCapabilities( NULL ) { - mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) ); + mIcon = QIcon( getThemePixmap( "mIconWfs.png" ) ); } QgsWFSConnectionItem::~QgsWFSConnectionItem() @@ -38,9 +39,10 @@ QVector QgsWFSConnectionItem::createChildren() { mGotCapabilities = false; - QgsOWSConnection connection( "WFS", mName ); - QgsDataSourceURI uri = connection.uri(); - QString encodedUri = uri.encodedUri(); + QString encodedUri = mPath; + QgsDataSourceURI uri; + uri.setEncodedUri ( encodedUri ); + QgsDebugMsg( "encodedUri = " + encodedUri ); mCapabilities = new QgsWFSCapabilities( encodedUri ); connect( mCapabilities, SIGNAL( gotCapabilities() ), this, SLOT( gotCapabilities() ) ); @@ -65,7 +67,8 @@ QVector QgsWFSConnectionItem::createChildren() } else { - layers.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); + //layers.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); + // TODO: show the error without adding child } mCapabilities->deleteLater(); @@ -136,7 +139,9 @@ QVector QgsWFSRootItem::createChildren() foreach( QString connName, QgsOWSConnection::connectionList( "WFS" ) ) { - QgsDataItem * conn = new QgsWFSConnectionItem( this, connName, mPath + "/" + connName ); + QgsOWSConnection connection( "WF", connName ); + QgsDataItem * conn = new QgsWFSConnectionItem( this, connName, connection.uri().encodedUri() ); + conn->setIcon ( QIcon( getThemePixmap( "mIconConnect.png" ) ) ); connections.append( conn ); } return connections; @@ -190,8 +195,12 @@ QGISEXTERN int dataCapabilities() QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) { - Q_UNUSED( thePath ); + QgsDebugMsg( "thePath = " + thePath ); + if ( thePath.isEmpty() ) + { + return new QgsWFSRootItem( parentItem, "WFS", "wfs:" ); + } - return new QgsWFSRootItem( parentItem, "WFS", "wfs:" ); + return new QgsWFSConnectionItem( parentItem, "WFS", thePath ); } diff --git a/src/providers/wms/qgswmsdataitems.cpp b/src/providers/wms/qgswmsdataitems.cpp index ab9c2dcc80c..8214f2327e4 100644 --- a/src/providers/wms/qgswmsdataitems.cpp +++ b/src/providers/wms/qgswmsdataitems.cpp @@ -12,7 +12,7 @@ QgsWMSConnectionItem::QgsWMSConnectionItem( QgsDataItem* parent, QString name, QString path ) : QgsDataCollectionItem( parent, name, path ) { - mIcon = QIcon( getThemePixmap( "mIconConnect.png" ) ); + mIcon = QIcon( getThemePixmap( "mIconWms.png" ) ); } QgsWMSConnectionItem::~QgsWMSConnectionItem() @@ -23,18 +23,33 @@ QVector QgsWMSConnectionItem::createChildren() { QgsDebugMsg( "Entered" ); QVector children; - QgsWMSConnection connection( mName ); - QgsWmsProvider *wmsProvider = connection.provider( ); - if ( !wmsProvider ) - return children; - QgsDataSourceURI uri = connection.uri(); - QgsDebugMsg( "uri = " + uri.encodedUri() ); + QString encodedUri = mPath; + QgsDataSourceURI uri; + uri.setEncodedUri ( encodedUri ); +/* + if ( mPath.contains ( "url=" ) ) + { + encodedUri = mPath; + uri.setEncodedUri ( encodedUri ); + } + else + { + QgsWMSConnection connection( mName ); + uri = connection.uri(); + encodedUri = uri.encodedUri(); + } +*/ + QgsDebugMsg( "encodedUri = " + encodedUri ); + + QgsWmsProvider *wmsProvider = new QgsWmsProvider ( encodedUri ); + if ( !wmsProvider ) return children; // Attention: supportedLayers() gives tree leafes, not top level if ( !wmsProvider->supportedLayers( mLayerProperties ) ) { - children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); + //children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) ); + // TODO: show the error without adding child return children; } @@ -65,7 +80,12 @@ bool QgsWMSConnectionItem::equal( const QgsDataItem *other ) return false; } const QgsWMSConnectionItem *o = dynamic_cast( other ); - return ( mPath == o->mPath && mName == o->mName && mConnInfo == o->mConnInfo ); + if ( !o ) + { + return false; + } + + return ( mPath == o->mPath && mName == o->mName ); } QList QgsWMSConnectionItem::actions() @@ -126,7 +146,8 @@ QgsWMSLayerItem::QgsWMSLayerItem( QgsDataItem* parent, QString name, QString pat if ( mChildren.size() == 0 ) { - mIcon = iconRaster(); + //mIcon = iconRaster(); + mIcon = QIcon( getThemePixmap( "mIconWms.png" ) ); } mPopulated = true; } @@ -199,7 +220,11 @@ QVectorQgsWMSRootItem::createChildren() foreach( QString connName, QgsWMSConnection::connectionList() ) { - QgsDataItem * conn = new QgsWMSConnectionItem( this, connName, mPath + "/" + connName ); + //QgsDataItem * conn = new QgsWMSConnectionItem( this, connName, mPath + "/" + connName ); + QgsWMSConnection connection( connName ); + QgsDataItem * conn = new QgsWMSConnectionItem( this, connName, connection.uri().encodedUri() ); + + conn->setIcon ( QIcon( getThemePixmap( "mIconConnect.png" ) ) ); connections.append( conn ); } return connections; @@ -253,7 +278,11 @@ QGISEXTERN int dataCapabilities() QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) { - Q_UNUSED( thePath ); + if ( thePath.isEmpty() ) + { + return new QgsWMSRootItem( parentItem, "WMS", "wms:" ); + } - return new QgsWMSRootItem( parentItem, "WMS", "wms:" ); + // The path should contain encoded connection URI + return new QgsWMSConnectionItem( parentItem, "WMS", thePath ); } From 27cfe7c1166aaf45f3d161f1602545ac0ad6306d Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 2 May 2012 10:52:07 +0200 Subject: [PATCH 16/19] WCS 1.0 GetCapabilities parser --- src/providers/gdal/qgsgdaldataitems.cpp | 32 +- src/providers/gdal/qgsgdalprovider.cpp | 6 +- src/providers/gdal/qgswcscapabilities.cpp | 553 +++++++++++++++------- src/providers/gdal/qgswcscapabilities.h | 45 +- src/providers/gdal/qgswcssourceselect.cpp | 45 +- src/providers/gdal/qgswcssourceselect.h | 6 +- 6 files changed, 475 insertions(+), 212 deletions(-) diff --git a/src/providers/gdal/qgsgdaldataitems.cpp b/src/providers/gdal/qgsgdaldataitems.cpp index f572a420579..48649719adb 100644 --- a/src/providers/gdal/qgsgdaldataitems.cpp +++ b/src/providers/gdal/qgsgdaldataitems.cpp @@ -65,7 +65,7 @@ QgsWCSConnectionItem::QgsWCSConnectionItem( QgsDataItem* parent, QString name, Q QgsWCSConnectionItem::~QgsWCSConnectionItem() { - QgsDebugMsg( "Entered"); + QgsDebugMsg( "Entered" ); } QVector QgsWCSConnectionItem::createChildren() @@ -75,7 +75,7 @@ QVector QgsWCSConnectionItem::createChildren() QString encodedUri = mPath; QgsDataSourceURI uri; - uri.setEncodedUri ( encodedUri ); + uri.setEncodedUri( encodedUri ); QgsDebugMsg( "encodedUri = " + encodedUri ); mCapabilities.setUri( uri ); @@ -108,7 +108,7 @@ bool QgsWCSConnectionItem::equal( const QgsDataItem *other ) return false; } const QgsWCSConnectionItem *o = dynamic_cast( other ); - if ( !o ) + if ( !o ) { return false; } @@ -190,6 +190,12 @@ QString QgsWCSLayerItem::createUri() // 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(); @@ -209,7 +215,10 @@ QString QgsWCSLayerItem::createUri() } } } - mDataSourceUri.setParam( "format", format ); + if ( !format.isEmpty() ) + { + mDataSourceUri.setParam( "format", format ); + } QString crs; @@ -229,7 +238,10 @@ QString QgsWCSLayerItem::createUri() { crs = mCoverageSummary.supportedCrs.value( 0 ); } - mDataSourceUri.setParam( "crs", crs ); + if ( !crs.isEmpty() ) + { + mDataSourceUri.setParam( "crs", crs ); + } return mDataSourceUri.encodedUri(); } @@ -257,7 +269,7 @@ QVectorQgsWCSRootItem::createChildren() QgsOWSConnection connection( "WCS", connName ); QgsDataItem * conn = new QgsWCSConnectionItem( this, connName, connection.uri().encodedUri() ); - conn->setIcon ( QIcon( getThemePixmap( "mIconConnect.png" ) ) ); + conn->setIcon( QIcon( getThemePixmap( "mIconConnect.png" ) ) ); connections.append( conn ); } return connections; @@ -310,17 +322,17 @@ QGISEXTERN int dataCapabilities() QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem ) { - QgsDebugMsg( "thePath = " + thePath ); + QgsDebugMsg( "thePath = " + thePath ); if ( thePath.isEmpty() ) { // Top level WCS return new QgsWCSRootItem( parentItem, "WCS", "wcs:" ); } - if ( thePath.contains ( "url=" ) ) + if ( thePath.contains( "url=" ) ) { - // OWS server - QgsDebugMsg( "connection found in uri" ); + // OWS server + QgsDebugMsg( "connection found in uri" ); return new QgsWCSConnectionItem( parentItem, "WCS", thePath ); } diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index b9dbaf0b7cf..8fd28212e34 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -146,7 +146,11 @@ QgsGdalProvider::QgsGdalProvider( QString const & uri ) // prepareUri adds ? or & if necessary, GDAL fails otherwise gdalUri += "" + Qt::escape( QgsWcsCapabilities::prepareUri( dsUri.param( "url" ) ) ) + ""; gdalUri += "" + dsUri.param( "identifier" ) + ""; - gdalUri += "" + dsUri.param( "format" ) + ""; + + if ( dsUri.hasParam( "format" ) ) + { + gdalUri += "" + dsUri.param( "format" ) + ""; + } // - 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). diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp index 9a7114f046f..c6568f90773 100644 --- a/src/providers/gdal/qgswcscapabilities.cpp +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -150,15 +150,53 @@ QString QgsWcsCapabilities::getCoverageUrl() const return url; } +bool QgsWcsCapabilities::sendRequest( QString const & url ) +{ + QgsDebugMsg( "url = " + url ); + mError = ""; + QNetworkRequest request( url ); + setAuthorization( request ); + request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork ); + request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); + + QgsDebugMsg( QString( "getcapabilities: %1" ).arg( url ) ); + mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); + + connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) ); + connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ) ); + + while ( mCapabilitiesReply ) + { + QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); + } + + if ( mCapabilitiesResponse.isEmpty() ) + { + if ( mError.isEmpty() ) + { + mErrorFormat = "text/plain"; + mError = tr( "empty capabilities document" ); + } + return false; + } + + if ( mCapabilitiesResponse.startsWith( "" ) || + mCapabilitiesResponse.startsWith( "" ) ) + { + mErrorFormat = "text/html"; + mError = mCapabilitiesResponse; + return false; + } + return true; +} + bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) { - QgsDebugMsg( "entering." ); - if ( mCapabilitiesResponse.isNull() || forceRefresh ) { // Check if user tried to force version QString userVersion = QUrl( mUri.param( "url" ) ).queryItemValue( "VERSION" ); - if ( !userVersion.isEmpty() && !userVersion.startsWith( "1.1." ) ) + if ( !userVersion.isEmpty() && !userVersion.startsWith( "1.0." ) ) { mErrorTitle = tr( "Version not supported" ); mErrorFormat = "text/plain"; @@ -166,43 +204,9 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) return false; } - QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities&VERSION=1.1.0"; + QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=GetCapabilities&VERSION=1.0.0"; - mError = ""; - - QNetworkRequest request( url ); - setAuthorization( request ); - request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork ); - request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); - - QgsDebugMsg( QString( "getcapabilities: %1" ).arg( url ) ); - mCapabilitiesReply = QgsNetworkAccessManager::instance()->get( request ); - - connect( mCapabilitiesReply, SIGNAL( finished() ), this, SLOT( capabilitiesReplyFinished() ) ); - connect( mCapabilitiesReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( capabilitiesReplyProgress( qint64, qint64 ) ) ); - - while ( mCapabilitiesReply ) - { - QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); - } - - if ( mCapabilitiesResponse.isEmpty() ) - { - if ( mError.isEmpty() ) - { - mErrorFormat = "text/plain"; - mError = tr( "empty capabilities document" ); - } - return false; - } - - if ( mCapabilitiesResponse.startsWith( "" ) || - mCapabilitiesResponse.startsWith( "" ) ) - { - mErrorFormat = "text/html"; - mError = mCapabilitiesResponse; - return false; - } + if ( ! sendRequest( url ) ) { return false; } QgsDebugMsg( "Converting to Dom." ); @@ -222,7 +226,45 @@ bool QgsWcsCapabilities::retrieveServerCapabilities( bool forceRefresh ) } } - QgsDebugMsg( "exiting." ); + return true; +} + +bool QgsWcsCapabilities::describeCoverage( QString const &identifier, bool forceRefresh ) +{ + QgsDebugMsg( " identifier = " + identifier ); + + if ( !mVersion.startsWith( "1.0." ) ) { return true; } // no need for 1.1 + + QgsWcsCoverageSummary *coverage = coverageSummary( identifier ); + if ( !coverage ) + { + QgsDebugMsg( "coverage not found" ); + return false; + } + + if ( coverage->described && ! forceRefresh ) return true; + + QString url = prepareUri( mUri.param( "url" ) ) + "SERVICE=WCS&REQUEST=DescribeCoverage&VERSION=1.0.0&COVERAGE=" + coverage->identifier; + + if ( ! sendRequest( url ) ) { return false; } + + QgsDebugMsg( "Converting to Dom." ); + + bool domOK; + domOK = parseDescribeCoverageDom( mCapabilitiesResponse, coverage ); + QgsDebugMsg( "supportedFormat = " + coverage->supportedFormat.join( "," ) ); + + if ( !domOK ) + { + // We had an Dom exception - + // mErrorTitle and mError are pre-filled by parseCapabilitiesDom + + mError += tr( "\nTried URL: %1" ).arg( url ); + + QgsDebugMsg( "!domOK: " + mError ); + + return false; + } return true; } @@ -284,8 +326,7 @@ QString QgsWcsCapabilities::stripNS( const QString & name ) bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapabilitiesProperty &capabilities ) { - QgsDebugMsg( "entering." ); - + QgsDebugMsg( "Entered." ); #ifdef QGISDEBUG QFile file( QDir::tempPath() + "/qgis-wcs-capabilities.xml" ); if ( file.open( QIODevice::WriteOnly ) ) @@ -295,26 +336,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa } #endif - // Convert completed document into a Dom - QString errorMsg; - int errorLine; - int errorColumn; - bool contentSuccess = mCapabilitiesDom.setContent( xml, false, &errorMsg, &errorLine, &errorColumn ); - - if ( !contentSuccess ) - { - mErrorTitle = tr( "Dom Exception" ); - mErrorFormat = "text/plain"; - mError = tr( "Could not get WCS capabilities: %1 at line %2 column %3\nThis is probably due to an incorrect WMS Server URL.\nResponse was:\n\n%4" ) - .arg( errorMsg ) - .arg( errorLine ) - .arg( errorColumn ) - .arg( QString( xml ) ); - - QgsLogger::debug( "Dom Exception: " + mError ); - - return false; - } + if ( ! convertToDom( xml ) ) return false; QDomElement docElem = mCapabilitiesDom.documentElement(); @@ -330,7 +352,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa { mErrorTitle = tr( "Dom Exception" ); mErrorFormat = "text/plain"; - mError = tr( "Could not get WCS capabilities in the expected format (DTD): no %1 found.\nThis might be due to an incorrect WMS Server URL.\nTag:%3\nResponse was:\n%4" ) + mError = tr( "Could not get WCS capabilities in the expected format (DTD): no %1 found.\nThis might be due to an incorrect WCS Server URL.\nTag:%3\nResponse was:\n%4" ) .arg( "Capabilities" ) .arg( docElem.tagName() ) .arg( QString( xml ) ); @@ -343,7 +365,7 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa capabilities.version = docElem.attribute( "version" ); mVersion = capabilities.version; - if ( !mVersion.startsWith( "1.1." ) ) + if ( !mVersion.startsWith( "1.0." ) ) { mErrorTitle = tr( "Version not supported" ); mErrorFormat = "text/plain"; @@ -355,192 +377,352 @@ bool QgsWcsCapabilities::parseCapabilitiesDom( QByteArray const &xml, QgsWcsCapa return false; } - // Start walking through XML. QDomNode n = docElem.firstChild(); while ( !n.isNull() ) { - QDomElement e = n.toElement(); // try to convert the node to an element. + QDomElement e = n.toElement(); if ( !e.isNull() ) { + // Version 1.0 QString tagName = stripNS( e.tagName() ); - if ( tagName == "ServiceIdentification" ) + QgsDebugMsg( tagName ); + if ( tagName == "Service" ) + { + parseService( e, capabilities.serviceIdentification ); + } + else if ( tagName == "Capability" ) + { + parseCapability( e, capabilities.operationsMetadata ); + } + else if ( tagName == "ContentMetadata" ) + { + parseContentMetadata( e, capabilities.contents ); + } + // Version 1.1 + else if ( tagName == "ServiceIdentification" ) { - QgsDebugMsg( " ServiceIdentification." ); parseServiceIdentification( e, capabilities.serviceIdentification ); } else if ( tagName == "OperationsMetadata" ) { - QgsDebugMsg( " OperationsMetadata." ); parseOperationsMetadata( e, capabilities.operationsMetadata ); } else if ( tagName == "Contents" ) { - QgsDebugMsg( " Contents." ); parseCoverageSummary( e, capabilities.contents ); } } n = n.nextSibling(); } - QgsDebugMsg( "exiting." ); - return true; } - -void QgsWcsCapabilities::parseServiceIdentification( QDomElement const & e, QgsWcsServiceIdentification &serviceIdentification ) +QDomElement QgsWcsCapabilities::firstChild( const QDomElement &element, const QString & name ) { - QgsDebugMsg( "entering." ); - - QDomNode n1 = e.firstChild(); + QDomNode n1 = element.firstChild(); while ( !n1.isNull() ) { - QDomElement el = n1.toElement(); // try to convert the node to an element. + QDomElement el = n1.toElement(); if ( !el.isNull() ) { QString tagName = stripNS( el.tagName() ); - - if ( tagName == "Title" ) + if ( tagName == name ) { - serviceIdentification.title = el.text(); - } - else if ( tagName == "Abstract" ) - { - serviceIdentification.abstract = el.text(); + QgsDebugMsg( name + " found" ); + return el; } } n1 = n1.nextSibling(); } + QgsDebugMsg( name + " not found" ); + return QDomElement(); +} - QgsDebugMsg( "exiting." ); +QString QgsWcsCapabilities::firstChildText( const QDomElement &element, const QString & name ) +{ + QDomElement el = firstChild( element, name ); + if ( !el.isNull() ) + { + QgsDebugMsg( name + " : " + el.text() ); + return el.text(); + } + return QString(); +} + +// ------------------------ 1.0 ---------------------------------------------- +void QgsWcsCapabilities::parseService( const QDomElement &e, QgsWcsServiceIdentification &serviceIdentification ) // 1.0 +{ + serviceIdentification.title = firstChildText( e, "name" ); + serviceIdentification.abstract = firstChildText( e, "description" ); + // 1.0 has also "label" +} + +void QgsWcsCapabilities::parseCapability( QDomElement const & e, QgsWcsOperationsMetadata &operationsMetadata ) +{ + QDomElement requestElement = firstChild( e, "Request" ); + QDomElement getCoverageElement = firstChild( requestElement, "GetCoverage" ); + QDomElement dcpTypeElement = firstChild( getCoverageElement, "DCPType" ); + QDomElement httpElement = firstChild( dcpTypeElement, "HTTP" ); + QDomElement getElement = firstChild( httpElement, "Get" ); + QDomElement onlineResourceElement = firstChild( getElement, "OnlineResource" ); + + operationsMetadata.getCoverage.dcp.http.get.xlinkHref = onlineResourceElement.attribute( "xlink:href" ); + + QgsDebugMsg( "getCoverage.dcp.http.get.xlinkHref = " + operationsMetadata.getCoverage.dcp.http.get.xlinkHref ); +} + +void QgsWcsCapabilities::parseContentMetadata( QDomElement const & e, QgsWcsCoverageSummary &coverageSummary ) +{ + QDomNode n1 = e.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); + if ( !el.isNull() ) + { + QString tagName = stripNS( el.tagName() ); + + if ( tagName == "CoverageOfferingBrief" ) + { + QgsWcsCoverageSummary subCoverageSummary; + + subCoverageSummary.described = false; + + parseCoverageOfferingBrief( el, subCoverageSummary, &coverageSummary ); + + coverageSummary.coverageSummary.push_back( subCoverageSummary ); + } + } + n1 = n1.nextSibling(); + } +} + +void QgsWcsCapabilities::parseCoverageOfferingBrief( QDomElement const & e, QgsWcsCoverageSummary &coverageSummary, QgsWcsCoverageSummary *parent ) +{ + QgsDebugMsg( "Entered" ); + coverageSummary.orderId = ++mCoverageCount; + + coverageSummary.identifier = firstChildText( e, "name" ); + coverageSummary.title = firstChildText( e, "label" ); + coverageSummary.abstract = firstChildText( e, "description" ); + + QDomElement lonLatEnvelopeElement = firstChild( e, "lonLatEnvelope" ); + + QDomNodeList posNodes = lonLatEnvelopeElement.elementsByTagName( "pos" ); + QList lon, lat; + for ( int i = 0; i < posNodes.size(); i++ ) + { + QDomNode posNode = posNodes.at( i ); + QString lonLatText = posNode.toElement().text(); + QStringList lonLat = lonLatText.split( QRegExp( " +" ) ); + if ( lonLat.size() != 2 ) + { + QgsDebugMsg( "Cannot parse lonLatEnvelope: " + lonLatText ); + continue; + } + double lo, la; + bool loOk, laOk; + lo = lonLat.value( 0 ).toDouble( &loOk ); + la = lonLat.value( 1 ).toDouble( &laOk ); + if ( loOk && laOk ) + { + lon << lo; + lat << la; + } + else + { + QgsDebugMsg( "Cannot parse lonLatEnvelope: " + lonLatText ); + } + } + if ( lon.size() == 2 ) + { + double w, e, s, n; + w = qMin( lon[0], lon[1] ); + e = qMax( lon[0], lon[1] ); + n = qMax( lat[0], lat[1] ); + s = qMin( lat[0], lat[1] ); + + coverageSummary.wgs84BoundingBox = QgsRectangle( w, s, e, n ); + QgsDebugMsg( "wgs84BoundingBox = " + coverageSummary.wgs84BoundingBox.toString() ); + } + + if ( !coverageSummary.identifier.isEmpty() ) + { + QgsDebugMsg( "add coverage " + coverageSummary.identifier + " to supported" ); + mCoveragesSupported.push_back( coverageSummary ); + } + + if ( !coverageSummary.coverageSummary.empty() ) + { + mCoverageParentIdentifiers[ coverageSummary.orderId ] = QStringList() << coverageSummary.identifier << coverageSummary.title << coverageSummary.abstract; + } + QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2" ).arg( coverageSummary.orderId ).arg( coverageSummary.identifier ) ); +} + +bool QgsWcsCapabilities::convertToDom( QByteArray const &xml ) +{ + QgsDebugMsg( "Entered." ); + // Convert completed document into a Dom + QString errorMsg; + int errorLine; + int errorColumn; + bool contentSuccess = mCapabilitiesDom.setContent( xml, false, &errorMsg, &errorLine, &errorColumn ); + + if ( !contentSuccess ) + { + mErrorTitle = tr( "Dom Exception" ); + mErrorFormat = "text/plain"; + mError = tr( "Could not get WCS capabilities: %1 at line %2 column %3\nThis is probably due to an incorrect WCS Server URL.\nResponse was:\n\n%4" ) + .arg( errorMsg ) + .arg( errorLine ) + .arg( errorColumn ) + .arg( QString( xml ) ); + + QgsLogger::debug( "Dom Exception: " + mError ); + + return false; + } + return true; +} + +bool QgsWcsCapabilities::parseDescribeCoverageDom( QByteArray const &xml, QgsWcsCoverageSummary *coverage ) +{ + QgsDebugMsg( "coverage->identifier = " + coverage->identifier ); + if ( ! convertToDom( xml ) ) return false; + + QDomElement docElem = mCapabilitiesDom.documentElement(); + + QgsDebugMsg( "testing tagName " + docElem.tagName() ); + + QString tagName = stripNS( docElem.tagName() ); + if ( tagName != "CoverageDescription" ) + { + mErrorTitle = tr( "Dom Exception" ); + mErrorFormat = "text/plain"; + mError = tr( "Could not get WCS capabilities in the expected format (DTD): no %1 found.\nThis might be due to an incorrect WCS Server URL.\nTag:%3\nResponse was:\n%4" ) + .arg( "CoverageDescription" ) + .arg( docElem.tagName() ) + .arg( QString( xml ) ); + + QgsLogger::debug( "Dom Exception: " + mError ); + + return false; + } + + QDomElement coverageOfferingElement = firstChild( docElem, "CoverageOffering" ); + + if ( coverageOfferingElement.isNull() ) return false; + QDomElement supportedCRSsElement = firstChild( coverageOfferingElement, "supportedCRSs" ); + + QDomNode n1 = supportedCRSsElement.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); + if ( !el.isNull() ) + { + QString tagName = stripNS( el.tagName() ); + + if ( tagName == "requestResponseCRSs" ) + { + coverage->supportedCrs << el.text(); + } + } + n1 = n1.nextSibling(); + } + QgsDebugMsg( "supportedCrs = " + coverage->supportedCrs.join( "," ) ); + + QDomElement supportedFormatsElement = firstChild( coverageOfferingElement, "supportedFormats" ); + + n1 = supportedFormatsElement.firstChild(); + while ( !n1.isNull() ) + { + QDomElement el = n1.toElement(); + if ( !el.isNull() ) + { + QString tagName = stripNS( el.tagName() ); + + if ( tagName == "formats" ) + { + // TODO: map other formats to GDAL mime types + QString format = el.text().toLower(); + if ( format == "geotiff" || format == "gtiff" || format == "tiff" || format == "tif" ) + { + coverage->supportedFormat << "image/tiff"; + } + } + } + n1 = n1.nextSibling(); + } + QgsDebugMsg( "supportedFormat = " + coverage->supportedFormat.join( "," ) ); + + coverage->described = true; + + return true; +} +// ------------------------ 1.1 ---------------------------------------------- +void QgsWcsCapabilities::parseServiceIdentification( const QDomElement &e, QgsWcsServiceIdentification &serviceIdentification ) // 1.1 +{ + serviceIdentification.title = firstChildText( e, "Title" ); + serviceIdentification.abstract = firstChildText( e, "Abstract" ); } void QgsWcsCapabilities::parseHttp( QDomElement const & e, QgsWcsHTTP& http ) { - QgsDebugMsg( "entering." ); - - QDomNode n1 = e.firstChild(); - while ( !n1.isNull() ) - { - QDomElement el = n1.toElement(); // try to convert the node to an element. - if ( !el.isNull() ) - { - QString tagName = stripNS( el.tagName() ); - if ( tagName == "Get" ) - { - QgsDebugMsg( " Get." ); - http.get.xlinkHref = el.attribute( "xlink:href" ); - } - } - n1 = n1.nextSibling(); - } - - QgsDebugMsg( "exiting." ); + http.get.xlinkHref = firstChild( e, "Get" ).attribute( "xlink:href" ); + QgsDebugMsg( "http.get.xlinkHref = " + http.get.xlinkHref ); } void QgsWcsCapabilities::parseDcp( QDomElement const & e, QgsWcsDCP& dcp ) { - QgsDebugMsg( "entering." ); - - QDomNode n1 = e.firstChild(); - while ( !n1.isNull() ) - { - QDomElement el = n1.toElement(); // try to convert the node to an element. - if ( !el.isNull() ) - { - QString tagName = stripNS( el.tagName() ); - if ( tagName == "HTTP" ) - { - QgsDebugMsg( " HTTP." ); - parseHttp( el, dcp.http ); - } - } - n1 = n1.nextSibling(); - } - - QgsDebugMsg( "exiting." ); + QDomElement el = firstChild( e, "HTTP" ); + parseHttp( el, dcp.http ); } void QgsWcsCapabilities::parseOperation( QDomElement const & e, QgsWcsOperation& operation ) { - QgsDebugMsg( "entering." ); - - QDomNode n1 = e.firstChild(); - while ( !n1.isNull() ) - { - QDomElement el = n1.toElement(); // try to convert the node to an element. - if ( !el.isNull() ) - { - QString tagName = stripNS( el.tagName() ); - - if ( tagName == "DCP" ) - { - QgsDebugMsg( " DCP." ); - parseDcp( el, operation.dcp ); - } - // TODO Parameter version - } - n1 = n1.nextSibling(); - } - - QgsDebugMsg( "exiting." ); + QDomElement el = firstChild( e, "DCP" ); + parseDcp( el, operation.dcp ); } void QgsWcsCapabilities::parseOperationsMetadata( QDomElement const & e, QgsWcsOperationsMetadata &operationsMetadata ) { - QgsDebugMsg( "entering." ); - QDomNode n1 = e.firstChild(); while ( !n1.isNull() ) { - QDomElement el = n1.toElement(); // try to convert the node to an element. + QDomElement el = n1.toElement(); if ( !el.isNull() ) { QString tagName = stripNS( el.tagName() ); - if ( tagName == "GetCoverage" ) + if ( tagName == "Operation" && el.attribute( "name" ) == "GetCoverage" ) { - QgsDebugMsg( " GetCoverage." ); parseOperation( el, operationsMetadata.getCoverage ); } } n1 = n1.nextSibling(); } - - QgsDebugMsg( "exiting." ); } void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCoverageSummary &coverageSummary, QgsWcsCoverageSummary *parent ) { - QgsDebugMsg( "entering." ); - coverageSummary.orderId = ++mCoverageCount; + coverageSummary.identifier = firstChildText( e, "Identifier" ); + coverageSummary.title = firstChildText( e, "Title" ); + coverageSummary.abstract = firstChildText( e, "Abstract" ); + QDomNode n1 = e.firstChild(); while ( !n1.isNull() ) { - QDomElement el = n1.toElement(); // try to convert the node to an element. + QDomElement el = n1.toElement(); if ( !el.isNull() ) { QString tagName = stripNS( el.tagName() ); QgsDebugMsg( tagName + " : " + el.text() ); - if ( tagName == "Identifier" ) - { - coverageSummary.identifier = el.text(); - QgsDebugMsg( "Identifier = " + el.text() ); - } - else if ( tagName == "Title" ) - { - coverageSummary.title = el.text(); - } - else if ( tagName == "Abstract" ) - { - coverageSummary.abstract = el.text(); - } - else if ( tagName == "SupportedFormat" ) + if ( tagName == "SupportedFormat" ) { coverageSummary.supportedFormat << el.text(); } @@ -581,7 +763,7 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove n1 = e.firstChild(); while ( !n1.isNull() ) { - QDomElement el = n1.toElement(); // try to convert the node to an element. + QDomElement el = n1.toElement(); if ( !el.isNull() ) { QString tagName = stripNS( el.tagName() ); @@ -622,7 +804,6 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove } QgsDebugMsg( QString( "coverage orderId = %1 identifier = %2" ).arg( coverageSummary.orderId ).arg( coverageSummary.identifier ) ); - QgsDebugMsg( "exiting." ); } void QgsWcsCapabilities::coverageParents( QMap &parents, QMap &parentNames ) const @@ -665,13 +846,31 @@ void QgsWcsCapabilities::showMessageBox( const QString& title, const QString& te message->showMessage(); } -QgsWcsCoverageSummary QgsWcsCapabilities::coverageSummary( QString const & theIdentifier ) +QgsWcsCoverageSummary* QgsWcsCapabilities::coverageSummary( QString const & theIdentifier, QgsWcsCoverageSummary* parent ) { - QgsDebugMsg( "entered" ); - foreach( QgsWcsCoverageSummary c, mCoveragesSupported ) + QgsDebugMsg( "theIdentifier = " + theIdentifier ); + if ( !parent ) { - if ( c.identifier == theIdentifier ) return c; + parent = &( mCapabilities.contents ); } - QgsWcsCoverageSummary c; - return c; + + //foreach( const QgsWcsCoverageSummary &c, parent->coverageSummary ) + for ( QVector::iterator c = parent->coverageSummary.begin(); c != parent->coverageSummary.end(); ++c ) + { + QgsDebugMsg( "c->identifier = " + c->identifier ); + if ( c->identifier == theIdentifier ) + { + return c; + } + else + { + // search sub coverages + QgsWcsCoverageSummary * sc = coverageSummary( theIdentifier, c ); + if ( sc ) + { + return sc; + } + } + } + return 0; } diff --git a/src/providers/gdal/qgswcscapabilities.h b/src/providers/gdal/qgswcscapabilities.h index 60f1e92cf16..3a16bc1943f 100644 --- a/src/providers/gdal/qgswcscapabilities.h +++ b/src/providers/gdal/qgswcscapabilities.h @@ -96,6 +96,7 @@ struct QgsWcsCoverageSummary QStringList supportedFormat; QgsRectangle wgs84BoundingBox; QVector coverageSummary; + bool described; // 1.0 }; /** Contents structure */ @@ -136,8 +137,6 @@ class QgsWcsCapabilities : public QObject * otherwise we contact the host directly. * */ - //QgsWcsCapabilities( QString const & theUri = 0 ); - QgsWcsCapabilities( QgsDataSourceURI const & theUri ); QgsWcsCapabilities( ); @@ -158,13 +157,14 @@ class QgsWcsCapabilities : public QObject */ bool supportedCoverages( QVector &coverageSummary ); + /** * \brief Returns a map for the hierarchy of layers */ void coverageParents( QMap &parents, QMap &parentNames ) const; //! Get coverage summare for identifier - QgsWcsCoverageSummary coverageSummary( QString const & theIdentifier ); + QgsWcsCoverageSummary * coverageSummary( QString const & theIdentifier, QgsWcsCoverageSummary* parent = 0 ); /** * \brief Prepare the URI so that we can later simply append param=value @@ -178,6 +178,17 @@ class QgsWcsCapabilities : public QObject */ 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; @@ -219,10 +230,16 @@ class QgsWcsCapabilities : public QObject void capabilitiesReplyProgress( qint64, qint64 ); private: - void showMessageBox( const QString& title, const QString& text ); + void showMessageBox( const QString &title, const QString &text ); //! Get tag name without namespace - QString stripNS( const QString & name ); + 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 @@ -241,10 +258,25 @@ class QgsWcsCapabilities : public QObject //! \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 parseServiceIdentification( QDomElement const &e, QgsWcsServiceIdentification &serviceIdentification ); + 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 @@ -288,6 +320,7 @@ class QgsWcsCapabilities : public QObject /** * layers hosted by the WCS Server + * This vector contain initial copies which are not updated by coverageSummary()!!! */ QVector mCoveragesSupported; diff --git a/src/providers/gdal/qgswcssourceselect.cpp b/src/providers/gdal/qgswcssourceselect.cpp index 2f243a60bab..50369b356e4 100644 --- a/src/providers/gdal/qgswcssourceselect.cpp +++ b/src/providers/gdal/qgswcssourceselect.cpp @@ -109,15 +109,22 @@ void QgsWCSSourceSelect::populateLayerList( ) } } +QString QgsWCSSourceSelect::selectedIdentifier() +{ + QList 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; - QList selectionList = mLayersTreeWidget->selectedItems(); - if ( selectionList.size() < 1 ) return; // should not happen - QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString(); - QgsDebugMsg( " identifier = " + identifier ); + QString identifier = selectedIdentifier(); + if ( identifier.isEmpty() ) { return; } uri.setParam( "identifier", identifier ); @@ -138,6 +145,12 @@ void QgsWCSSourceSelect::addClicked( ) void QgsWCSSourceSelect::on_mLayersTreeWidget_itemSelectionChanged() { QgsDebugMsg( "entered" ); + + QString identifier = selectedIdentifier(); + if ( identifier.isEmpty() ) { return; } + + mCapabilities.describeCoverage( identifier ); // 1.0 get additional info + populateFormats(); populateCRS(); @@ -194,27 +207,27 @@ QStringList QgsWCSSourceSelect::selectedLayersFormats() { QgsDebugMsg( "entered" ); - QList selectionList = mLayersTreeWidget->selectedItems(); - if ( selectionList.size() < 1 ) return QStringList(); - QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString(); - QgsDebugMsg( " identifier = " + identifier ); + QString identifier = selectedIdentifier(); + if ( identifier.isEmpty() ) { return QStringList(); } - QgsWcsCoverageSummary c = mCapabilities.coverageSummary( identifier ); - return c.supportedFormat; + QgsWcsCoverageSummary * c = mCapabilities.coverageSummary( identifier ); + if ( !c ) { return QStringList(); } + + QgsDebugMsg( "supportedFormat = " + c->supportedFormat.join( "," ) ); + return c->supportedFormat; } QStringList QgsWCSSourceSelect::selectedLayersCRSs() { QgsDebugMsg( "entered" ); - QList selectionList = mLayersTreeWidget->selectedItems(); - if ( selectionList.size() < 1 ) return QStringList(); - QString identifier = selectionList.value( 0 )->data( 0, Qt::UserRole + 0 ).toString(); - QgsDebugMsg( " identifier = " + identifier ); + QString identifier = selectedIdentifier(); + if ( identifier.isEmpty() ) { return QStringList(); } - QgsWcsCoverageSummary c = mCapabilities.coverageSummary( identifier ); + QgsWcsCoverageSummary * c = mCapabilities.coverageSummary( identifier ); + if ( !c ) { return QStringList(); } - return c.supportedCrs; + return c->supportedCrs; } void QgsWCSSourceSelect::enableLayersForCrs( QTreeWidgetItem *item ) diff --git a/src/providers/gdal/qgswcssourceselect.h b/src/providers/gdal/qgswcssourceselect.h index bfb4f4ad3cc..1ebf7e19908 100644 --- a/src/providers/gdal/qgswcssourceselect.h +++ b/src/providers/gdal/qgswcssourceselect.h @@ -5,7 +5,7 @@ original : (C) 2005 by Brendan Morley email : morb at ozemail dot com dot au wms search : (C) 2009 Mathias Walker , Sourcepole AG generalized : (C) 2012 Radim Blazek, based on qgsowsconnection.h - + ***************************************************************************/ /*************************************************************************** @@ -48,7 +48,7 @@ class QDomElement; */ class QgsWCSSourceSelect : public QgsOWSSourceSelect { - Q_OBJECT + Q_OBJECT public: //! Constructor @@ -66,6 +66,8 @@ class QgsWCSSourceSelect : public QgsOWSSourceSelect private: QgsWcsCapabilities mCapabilities; + QString selectedIdentifier(); + // QgsWcsCapabilities virtual methods void populateLayerList( ); void addClicked(); From 678147ccb2133f5dc61c18c16328195917b6c03b Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 2 May 2012 11:17:17 +0200 Subject: [PATCH 17/19] better add WCS layer icon --- images/themes/default/mActionAddWcsLayer.png | Bin 2060 -> 2085 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/themes/default/mActionAddWcsLayer.png b/images/themes/default/mActionAddWcsLayer.png index 20d8ada93e78b80d6cfa02d3474af482303858c1..549ecc7ffadc199da16a098b0d99913da665fc8b 100644 GIT binary patch delta 2012 zcmV<22P6255Ty{1Uw;Jx2@VduD+&n!00*T>L_t(o!^M|rY+c0_$A4$;eeb@_e$VfD ziR0K#Y$tM^k_AkX0)dh=i3?4sP$L?;M1-YM7g|-7prx%4RZ+hbp@OKWDpf_HC9P=1 z5*D>3#Gxg$K#1%l#U_LVJMn_;xB2-kcV_y*QGyTwyCC&Q_kY8^nmhBGGv|NK8Tj~2 z@qe%{xbeWt;f2wBd`XR|YN<9}gE!@boqa&}TqcnJabd@aID3*Eb(^E>qayVdH*T@Y zP|j+~Lz?UpSz8#Lz6YQ0f7}30s4hH~x_Ch{xIz&Pg9Jf>7F>gM3|eV2Gn)LvMe>8W zmvm0AJMU!kUVlB}Jlt@3^O{JPizl;NXi7BE7+**#T8FVdWnCl`1i4UQ24qobyfg$H z{5S$yvPY(@C)6}Pc#`=jjI_9#8=*ML!oRm7Acyxk*M=RE*KJ~Dut z2s{{Hm6U)8Rtp#bD`4I=$N*X)M&THTc*-HRHWmbK|9{8;ULyQS2@7J+ENnr{d&0=f zf{9Ux5dzl1?Qn6b-Hq?Nsrdi|BcUo$@Tp~&a>JE7W^A; z51+r4bp04k#O>5se|`Y1ZQJWNZ|c5k$&$vNa%pT-uIv8L<`M{ zmUCWHVSfTqg{z#Z@?1U8+O|D;$tBAl`E1XcO&hPg5U^yj1%CObA7S*Y>*s7*&}oIS zW@1i9(Av3U^Ukkr-rarCvc%H1Mnnn5!c4JD5Ep#dd+2%kPV^&=1!cMIn%h{@u?B$O z?*9#Yjy#SE06`cljKe#MO0M$ShXO2K{q@_wd4FTi-P^9YRFnwEPmbYE<~TAiL`zdG z9Sb`dDvpqL^JHi8h+`243Z=r?IVPtkIX-e630fQvib0D%;G^^YUp`O;9hZHtyK{Nl z&%8)P29J-Tjit4vo`!}R+S{6NgF){5#jnU79>@5z(Qe->K{%rh!B)VpKzUe5ADWy5 zet&)5OxU*J2LUedconwO5xb1`*+JyVLAQt)OfSS*^MLoqvPO zq)y?VE)wpD5gS{9ZrMo1*XUxN?6CtBGe>Zo3|=t6;)bQ18q>Rm`u5)p6hAb*AABQM zx_PUIC=DX4*_7bez8oF#I7!FhCbyOQ$P-%?L$HhvJV%Wmmn zvw`&Ky{xSyc|ErNTn21NfSMJR7YQ$)a~~JK_;YVP_I4k8GJQOi?xWW~%0J^rD5@OF zDUt|O_*SHuT0etW9|<}{n(H{6*+(KC#)(9baF~4q<5&?8A+L$g8DMeO>VFr~69(gI zw5!22oJ@`}Se`%$_!w4Jr?`5!nOJlRFHpvD1&J%{se9?^s-dx=hGzyR*tzQ!9`7H) z@q%y68DOxWp7BE$pr-{@bdjP0dUfRyr?b5tv7nTYkNfQ1m*I-KMk>Zo zu&~3qjPHyH>6#`e2{!2R*61KL_ufJK&bxR!TcWwPiWBML3v>3s;cu_2Eb3f6FfF3F^(oqGlU&@kfEU#Wt^`22Smm-TQq5P5gL3OI(N=V%l}OiBJbyb{#o(Ubk&H)C zfk5TSlhaSl>oQ?#>Tek?M3^ob3ME6KWXa?;TY8c_IXX~e z8zvL6pRR0+M^&}4Wn*no8!&DlFca;nTNGayTi4aHv~@wUF%pePKASt;``q4Vo;*76 u*7)SqG$J6%AWY+zg<^ILzx>h%0sI$Evo?7FUE9h400003jij-TtZm@00)doL_t(o!^M|rjGa{($A9OXce(GqckVK` zvv16FoNjbVJ7u~Eg<3k+A|eE%6VX!R5<@V4P-{@5_`&!^Ofy-&uAXZ5HlcK#cSs4Qkz8{IRB-Y#TsX(`h zr3Gk-t_r?-%Qm(T?_m2UcCcywo#0D^mV~9m8Md(+>_>p$dj?>{%txa))C*Gxv?st9 zpauB?0I-6AIw4_A-v`;ce#=Y>3+Qd?ee2FW{lnZke**}O7VzK;Um@K%feIQ6 zy=-l60J?gH8;3To+}z#WvdOI!`X71zds1jfgc1z&47}r;j#wuhvCe;cO*)t%i6K>; zJ6jKQ^?wZ4uU)(3*B{w5xN*b!6@Vs_E%KA!d>h}Jas8~t6L@Kful?y+g`jKUmZ8sm zcIc^<1AVa%^t2$Pz}HYJyI2@dgTEbmfg|USB9sQH*>>kP273nq_~na_@!au0AWgu6 ziQ*(oNvgT(Ywrr+%suzZtru$F|JbKDK6v+CH-8HyC1)>8U?g)KKRHHc+dO((7cy2J zCvD`(mhuRt5ekZx;#&%ng(PRk&mt_1vY~8gYA0)W`Py%GXl3)5vckID- zH!V(&j8OADx;h(aYKk+zrwzlh`00;+M)uewer+b(_1jAj-mDIRu0pK}?nOcRP%;Vp z{C}#Q@V5cv_H3 zk5a9bar_FIk*ATx0vr08N$rVou9_s!8h=I$c=qMrBNZThv;@x(xM|4k$?5d@1sD$x(MKgi(-e zNY?1Rsew#m0^PNlo<(aBQt|YQBY*Y}wyZ19YQAKO*<~l))4Y^9O<>*{7GG{5l(AWH zqKnD?B54~;r-gumN+pGra7iyOP#P@}fT4ELyk&!U|K!Ij6NirP7S-2iA(MxS~ z4^?ZNbhLo*6lFXPy|Rl^M*wAq-k7xqPL?~L^_%aA^gn@&SR7QRpH} zm#3K@sbHEG;r10omv5nd@P7-4&XrK-VJc0%UByLXJND681Mr;0;iJX4n@+4|cjyi# z#5~;k8q@t{eBn{m9=nnkczWyr;}ZulbqU)taiWa`n-|cw`jZ6vHY22@MJDNpKt&pV zpLGb1J+QiZ*Nzj1whp%6=+-*e@s~WC+&?3mYUG*>4mhVcSbiNtD1R>cVLUU8Wk`gW zSwyrEWnX+f7n>VMx{~&~>#92sPW@?4WFjNX2a>MVwq>%se=TpwPNeXt%qvlxSHY5s z<%vbauiMO}lEzXJTS;ssNLGA`(xTS1j8b9|yQjP#9{v2X?3@7n_3oa%-+e9f<6W04 zbT!m7X0?M5lv*s7Ie#5&YFSTW;5&qx`iKNfOeL|DpzK4^)kGYNV8B9J*2zfNd1y|1 z=D!YUjBh=0zH1Lqy|^BmyS!fWnY7$bAitsW59$5!yRl z=H6%4HF(#==MI0gsjT7l1F72H Date: Wed, 2 May 2012 19:16:48 +0200 Subject: [PATCH 18/19] Better formats in QgsOWSSourceSelect --- src/gui/qgsowssourceselect.cpp | 124 ++++++++++++++++------ src/gui/qgsowssourceselect.h | 15 +-- src/providers/gdal/qgswcscapabilities.cpp | 13 +-- 3 files changed, 105 insertions(+), 47 deletions(-) diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp index 31441d49685..88bcc88511f 100644 --- a/src/gui/qgsowssourceselect.cpp +++ b/src/gui/qgsowssourceselect.cpp @@ -120,57 +120,111 @@ QgsOWSSourceSelect::~QgsOWSSourceSelect() settings.setValue( "/Windows/WMSSourceSelect/geometry", saveGeometry() ); } +void QgsOWSSourceSelect::clearFormats() +{ + int i = 0; + while ( QRadioButton *btn = dynamic_cast( mImageFormatGroup->button( i++ ) ) ) + { + btn->setVisible( false ); + } +} + void QgsOWSSourceSelect::populateFormats() { QgsDebugMsg( "entered" ); + + // A server may offer more similar formats, which are mapped + // to the same GDAL format, e.g. GeoTIFF and TIFF + // -> recreate always buttons for all available formats, enable supported + + clearFormats(); + + QHBoxLayout *layout = dynamic_cast( mImageFormatsGroupBox->layout() ); + if ( !layout ) + { + layout = new QHBoxLayout; + mImageFormatsGroupBox->setLayout( layout ); + layout->addStretch(); + } + if ( mProviderFormats.size() == 0 ) { - QHBoxLayout *layout = new QHBoxLayout; - mProviderFormats = providerFormats(); - - // add buttons for available formats for ( int i = 0; i < mProviderFormats.size(); i++ ) { - mMimeMap.insert( mProviderFormats[i].format, i ); - - QRadioButton *btn = new QRadioButton( mProviderFormats[i].label ); - btn->setToolTip( mProviderFormats[i].format ); - mImageFormatGroup->addButton( btn, i ); - layout->addWidget( btn ); + // GDAL mime types may be image/tiff, image/png, ... + mMimeLabelMap.insert( mProviderFormats[i].format, mProviderFormats[i].label ); } - - layout->addStretch(); - mImageFormatsGroupBox->setLayout( layout ); } - // Show supported by server only - foreach( QAbstractButton *b, mImageFormatGroup->buttons() ) - { - b->setHidden( true ); - } + // selectedLayersFormats may come in various forms: + // image/tiff, GTiff, GeoTIFF, TIFF, PNG, GTOPO30, ARCGRID, IMAGEMOSAIC ... + QMap formatsMap; + formatsMap.insert( "geotiff", "tiff" ); + formatsMap.insert( "gtiff", "tiff" ); + formatsMap.insert( "tiff", "tiff" ); + formatsMap.insert( "tif", "tiff" ); + formatsMap.insert( "gif", "gif" ); + formatsMap.insert( "jpeg", "jpeg" ); + formatsMap.insert( "jpg", "jpeg" ); + formatsMap.insert( "png", "png" ); - int firstVisible = -1; - foreach( QString format, selectedLayersFormats() ) + int prefered = -1; + int firstEnabled = -1; + QStringList layersFormats = selectedLayersFormats(); + for ( int i = 0; i < layersFormats.size(); i++ ) { + QString format = layersFormats.value( i ); QgsDebugMsg( "server format = " + format ); - int id = mMimeMap.value( format, -1 ); - if ( id < 0 ) + QString simpleFormat = format.toLower().replace( "image/", "" ); + QgsDebugMsg( "server simpleFormat = " + simpleFormat ); + QString mimeFormat = "image/" + formatsMap.value( simpleFormat ); + QgsDebugMsg( "server mimeFormat = " + mimeFormat ); + + QString label = format; + QString tip = tr( "Server format" ) + " " + format; + + QRadioButton *btn; + btn = dynamic_cast( mImageFormatGroup->button( i ) ); + if ( !btn ) + { + btn = new QRadioButton( label ); + mImageFormatGroup->addButton( btn, i ); + layout->insertWidget( layout->count() - 1, btn ); // before stretch + } + btn->setVisible( true ); + + if ( mMimeLabelMap.contains( mimeFormat ) ) + { + btn->setEnabled( true ); + if ( format != mMimeLabelMap.value( mimeFormat ) ) + { + label += " / " + mMimeLabelMap.value( mimeFormat ); + } + tip += " " + tr( "is supported by GDAL %1 driver." ).arg( mMimeLabelMap.value( mimeFormat ) ); + if ( firstEnabled < 0 ) { firstEnabled = i; } + if ( simpleFormat.contains( "tif" ) ) // prefer *tif* + { + if ( prefered < 0 || simpleFormat.startsWith( "g" ) ) // prefere geotiff + { + prefered = i; + } + } + } + else { QgsDebugMsg( QString( "format %1 not supported." ).arg( format ) ); - continue; + btn->setEnabled( false ); + tip += " " + tr( "is not supported by GDAL" ); } - - mImageFormatGroup->button( id )->setVisible( true ); - if ( firstVisible == -1 ) firstVisible = id; + btn->setText( label ); + btn->setToolTip( tip ); } - // Set first if no one visible is checked - if ( mImageFormatGroup->checkedId() < 0 || !mImageFormatGroup->button( mImageFormatGroup->checkedId() )->isVisible() ) + // Set prefered + prefered = prefered >= 0 ? prefered : firstEnabled; + if ( prefered >= 0 ) { - if ( firstVisible > -1 ) - { - mImageFormatGroup->button( firstVisible )->setChecked( true ); - } + mImageFormatGroup->button( prefered )->setChecked( true ); } mImageFormatsGroupBox->setEnabled( true ); @@ -300,6 +354,10 @@ void QgsOWSSourceSelect::populateLayerList( ) void QgsOWSSourceSelect::on_mConnectButton_clicked() { QgsDebugMsg( "entered" ); + + mLayersTreeWidget->clear(); + clearFormats(); + mConnName = mConnectionsComboBox->currentText(); QgsOWSConnection connection( mService, mConnectionsComboBox->currentText() ); @@ -455,7 +513,7 @@ QString QgsOWSSourceSelect::selectedFormat() { // TODO: do format in subclass (WMS) //return QUrl::toPercentEncoding( mProviderFormats[ id ].format ); - return mProviderFormats[ id ].format; + return selectedLayersFormats().value( id ); } } diff --git a/src/gui/qgsowssourceselect.h b/src/gui/qgsowssourceselect.h index 0e6b300a98a..aa8f9d4670a 100644 --- a/src/gui/qgsowssourceselect.h +++ b/src/gui/qgsowssourceselect.h @@ -5,7 +5,7 @@ original : (C) 2005 by Brendan Morley email : morb at ozemail dot com dot au wms search : (C) 2009 Mathias Walker , Sourcepole AG generalized : (C) 2012 Radim Blazek, based on qgsowsconnection.h - + ***************************************************************************/ /*************************************************************************** @@ -115,7 +115,7 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase /** * List of image formats (encodings) supported by provider * @return list of format/label pairs - */ + */ virtual QList providerFormats(); //! List of formats supported for currently selected layer item(s) @@ -132,7 +132,10 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase //! Populate supported formats void populateFormats(); - //! Set supported CRSs + //! Clear previously set formats + void clearFormats(); + + //! Set supported CRSs void populateCRS(); //! Connection name @@ -160,7 +163,7 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase /** * \brief Populate the layer list. * - * \retval false if the layers could not be retrieved or parsed + * \retval false if the layers could not be retrieved or parsed */ virtual void populateLayerList( ); @@ -218,8 +221,8 @@ class QgsOWSSourceSelect : public QDialog, public Ui::QgsOWSSourceSelectBase //! Supported formats QList mProviderFormats; - //! Map mime types to supported formats - QMap mMimeMap; + //! Map mime type labels to supported formats + QMap mMimeLabelMap; private slots: void on_mSearchButton_clicked(); diff --git a/src/providers/gdal/qgswcscapabilities.cpp b/src/providers/gdal/qgswcscapabilities.cpp index c6568f90773..2c0ecb4c975 100644 --- a/src/providers/gdal/qgswcscapabilities.cpp +++ b/src/providers/gdal/qgswcscapabilities.cpp @@ -645,12 +645,8 @@ bool QgsWcsCapabilities::parseDescribeCoverageDom( QByteArray const &xml, QgsWcs if ( tagName == "formats" ) { - // TODO: map other formats to GDAL mime types - QString format = el.text().toLower(); - if ( format == "geotiff" || format == "gtiff" || format == "tiff" || format == "tif" ) - { - coverage->supportedFormat << "image/tiff"; - } + // may be GTiff, GeoTIFF, TIFF, GIF, .... + coverage->supportedFormat << el.text(); } } n1 = n1.nextSibling(); @@ -724,6 +720,7 @@ void QgsWcsCapabilities::parseCoverageSummary( QDomElement const & e, QgsWcsCove if ( tagName == "SupportedFormat" ) { + // image/tiff, ... coverageSummary.supportedFormat << el.text(); } else if ( tagName == "SupportedCRS" ) @@ -848,7 +845,7 @@ void QgsWcsCapabilities::showMessageBox( const QString& title, const QString& te QgsWcsCoverageSummary* QgsWcsCapabilities::coverageSummary( QString const & theIdentifier, QgsWcsCoverageSummary* parent ) { - QgsDebugMsg( "theIdentifier = " + theIdentifier ); + //QgsDebugMsg( "theIdentifier = " + theIdentifier ); if ( !parent ) { parent = &( mCapabilities.contents ); @@ -857,7 +854,7 @@ QgsWcsCoverageSummary* QgsWcsCapabilities::coverageSummary( QString const & theI //foreach( const QgsWcsCoverageSummary &c, parent->coverageSummary ) for ( QVector::iterator c = parent->coverageSummary.begin(); c != parent->coverageSummary.end(); ++c ) { - QgsDebugMsg( "c->identifier = " + c->identifier ); + //QgsDebugMsg( "c->identifier = " + c->identifier ); if ( c->identifier == theIdentifier ) { return c; From 70b68be64628009d2683a3c36cfb125a3a4a2a88 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 2 May 2012 19:35:57 +0200 Subject: [PATCH 19/19] WCS / OWS select format fix --- src/gui/qgsowssourceselect.cpp | 5 +++-- src/providers/gdal/qgswcssourceselect.cpp | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/qgsowssourceselect.cpp b/src/gui/qgsowssourceselect.cpp index 88bcc88511f..5b084334533 100644 --- a/src/gui/qgsowssourceselect.cpp +++ b/src/gui/qgsowssourceselect.cpp @@ -158,7 +158,8 @@ void QgsOWSSourceSelect::populateFormats() } // selectedLayersFormats may come in various forms: - // image/tiff, GTiff, GeoTIFF, TIFF, PNG, GTOPO30, ARCGRID, IMAGEMOSAIC ... + // image/tiff, GTiff, GeoTIFF, TIFF, geotiff_int16, geotiff_rgb, + // PNG, GTOPO30, ARCGRID, IMAGEMOSAIC, QMap formatsMap; formatsMap.insert( "geotiff", "tiff" ); formatsMap.insert( "gtiff", "tiff" ); @@ -176,7 +177,7 @@ void QgsOWSSourceSelect::populateFormats() { QString format = layersFormats.value( i ); QgsDebugMsg( "server format = " + format ); - QString simpleFormat = format.toLower().replace( "image/", "" ); + QString simpleFormat = format.toLower().replace( "image/", "" ).replace( QRegExp( "_.*" ), "" ); QgsDebugMsg( "server simpleFormat = " + simpleFormat ); QString mimeFormat = "image/" + formatsMap.value( simpleFormat ); QgsDebugMsg( "server mimeFormat = " + mimeFormat ); diff --git a/src/providers/gdal/qgswcssourceselect.cpp b/src/providers/gdal/qgswcssourceselect.cpp index 50369b356e4..3828a5d5dc0 100644 --- a/src/providers/gdal/qgswcssourceselect.cpp +++ b/src/providers/gdal/qgswcssourceselect.cpp @@ -137,7 +137,10 @@ void QgsWCSSourceSelect::addClicked( ) } QgsDebugMsg( "selectedFormat = " + selectedFormat() ); - uri.setParam( "format", selectedFormat() ); + if ( !selectedFormat().isEmpty() ) + { + uri.setParam( "format", selectedFormat() ); + } emit addRasterLayer( uri.encodedUri(), identifier, "gdal" ); }