704 changes: 704 additions & 0 deletions src/providers/gdal/qgswcscapabilities.cpp

Large diffs are not rendered by default.

391 changes: 391 additions & 0 deletions src/providers/gdal/qgswcscapabilities.h
Original file line number Diff line number Diff line change
@@ -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 <QString>
#include <QStringList>
#include <QDomElement>
#include <QMap>
#include <QVector>
#include <QUrl>

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

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

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

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

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

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

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

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

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

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

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

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

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

public:
/**
* Constructor for the provider.
*
* \param uri HTTP URL of the Web Server. If needed a proxy will be used
* otherwise we contact the host directly.
*
*/
//QgsWcsCapabilities( 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<QgsWcsCoverageSummary> &coverageSummary );

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

//! Get coverage summare for identifier
QgsWcsCoverageSummary coverageSummary ( QString const & theIdentifier );

/**
* 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<QgsWcsSupportedFormat> 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<QgsWcsCoverageSummary> mCoveragesSupported;

/**
* extents per layer (in WCS CRS:84 datum)
*/
//QMap<QString, QgsRectangle> extentForLayer;

/**
* available CRSs per layer
*/
//QMap<QString, QStringList > mCrsForLayer;

/**
* available formats per layer
*/
//QMap<QString, QStringList > 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<int, int> mCoverageParents;
QMap<int, QStringList> 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
246 changes: 246 additions & 0 deletions src/providers/gdal/qgswcssourceselect.cpp
Original file line number Diff line number Diff line change
@@ -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 <QWidget>

#define CPL_SUPRESS_CPLUSPLUS
#include <gdal.h>

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

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

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

QgsWCSSourceSelect::~QgsWCSSourceSelect()
{
}

bool QgsWCSSourceSelect::populateLayerList( )
{
QgsDebugMsg( "entered" );
// mCRSs.clear();

// TODO: showError

mCapabilities.setUri ( mUri );

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

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

mLayersTreeWidget->clear();
mLayersTreeWidget->setSortingEnabled( true );

int coverageAndStyleCount = -1;

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

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

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

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

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

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

return true;
}

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

QList<QTreeWidgetItem *> 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<QgsOWSSupportedFormat> QgsWCSSourceSelect::providerFormats()
{
QgsDebugMsg ( "entered");
QList<QgsOWSSupportedFormat> 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<QTreeWidgetItem *> 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<QTreeWidgetItem *> 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<QgsWcsCoverageSummary> 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
}
98 changes: 98 additions & 0 deletions src/providers/gdal/qgswcssourceselect.h
Original file line number Diff line number Diff line change
@@ -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 <mwa at sourcepole.ch>, Sourcepole AG
generalized : (C) 2012 Radim Blazek, based on qgsowsconnection.h
***************************************************************************/

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

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

#include "qgsdataprovider.h"

#include <QStringList>
#include <QPushButton>

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

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

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

public slots:

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

private:
QgsWcsCapabilities mCapabilities;

/**
* \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<QgsOWSSupportedFormat> providerFormats();

QStringList serverFormats();

QStringList serverCRS();

QStringList layerCRS( int id );

};
#endif // QGSWCSSOURCESELECT_H