wms update: - show nested layers in a tree - enable sorting in the wms dialog - use Qt instead of STL templates Index: src/app/qgsserversourceselect.h =================================================================== --- src/app/qgsserversourceselect.h (revision 9752) +++ src/app/qgsserversourceselect.h (working copy) @@ -21,13 +21,13 @@ #include "ui_qgsserversourceselectbase.h" #include "qgisgui.h" -#include -#include -#include +#include class QgisApp; class QgsWmsProvider; class QButtonGroup; +class QgsNumericSortTreeWidgetItem; + /*! * \brief Dialog to create connections and add layers from WMS, etc. * @@ -140,6 +140,9 @@ //! Populate the image encoding button group - private for now. void populateImageEncodingGroup( QgsWmsProvider* wmsProvider ); + //! 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 EpsgCrsId number QString descriptionForEpsg( long epsg ); @@ -165,7 +168,7 @@ QStringList m_selectedStylesForSelectedLayers; long m_Epsg; - std::map m_selectedStyleIdForLayer; + QMap m_selectedStyleIdForLayer; //! The mime type, the text to use in the button and a unique number QMap > m_PotentialFormats; Index: src/app/qgsserversourceselect.cpp =================================================================== --- src/app/qgsserversourceselect.cpp (revision 9752) +++ src/app/qgsserversourceselect.cpp (working copy) @@ -186,55 +186,87 @@ } -bool QgsServerSourceSelect::populateLayerList( QgsWmsProvider* wmsProvider ) +QgsNumericSortTreeWidgetItem *QgsServerSourceSelect::createItem( + int id, const QStringList &names, QMap &items, int &layerAndStyleCount, + const QMap &layerParents, const QMap &layerParentNames ) + { - std::vector layers; + if( items.contains(id) ) + return items[id]; + QgsNumericSortTreeWidgetItem *item; + if( layerParents.contains( id ) ) + { + int parent = layerParents[ id ]; + item = new QgsNumericSortTreeWidgetItem( createItem( parent, layerParentNames[ parent ], items, layerAndStyleCount, layerParents, layerParentNames ) ); + } + else + item = new QgsNumericSortTreeWidgetItem( lstLayers ); + + item->setText( 0, QString::number( ++layerAndStyleCount ) ); + item->setText( 1, names[0].simplified() ); + item->setText( 2, names[1].simplified() ); + item->setText( 3, names[2].simplified() ); + + items[ id ] = item; + + return item; +} + +bool QgsServerSourceSelect::populateLayerList( QgsWmsProvider *wmsProvider ) +{ + QVector layers; + if ( !wmsProvider->supportedLayers( layers ) ) { return FALSE; } + QMap items; + QMap layerParents; + QMap layerParentNames; + wmsProvider->layerParents( layerParents, layerParentNames ); + lstLayers->clear(); + lstLayers->setSortingEnabled( true ); - int layerAndStyleCount = 0; + int layerAndStyleCount = -1; - for ( std::vector::iterator layer = layers.begin(); + for ( QVector::iterator layer = layers.begin(); layer != layers.end(); layer++ ) { - // QgsDebugMsg(QString("got layer name %1 and title '%2'.").arg(layer->name).arg(layer->title)); + QgsNumericSortTreeWidgetItem *lItem = createItem(layer->orderId, QStringList() << layer->name << layer->title << layer->abstract, items, layerAndStyleCount, layerParents, layerParentNames ); - layerAndStyleCount++; + lItem->setData( 0, Qt::UserRole, layer->name ); + lItem->setData( 0, Qt::UserRole+1, "" ); - QgsNumericSortTreeWidgetItem *lItem = new QgsNumericSortTreeWidgetItem( lstLayers ); - lItem->setText( 0, QString::number( layerAndStyleCount ) ); - lItem->setText( 1, layer->name.simplified() ); - lItem->setText( 2, layer->title.simplified() ); - lItem->setText( 3, layer->abstract.simplified() ); - // Also insert the styles // Layer Styles - for ( uint j = 0; j < layer->style.size(); j++ ) + for ( int j = 0; j < layer->style.size(); j++ ) { QgsDebugMsg( QString( "got style name %1 and title '%2'." ).arg( layer->style[j].name ).arg( layer->style[j].title ) ); - layerAndStyleCount++; - QgsNumericSortTreeWidgetItem *lItem2 = new QgsNumericSortTreeWidgetItem( lItem ); - lItem2->setText( 0, QString::number( layerAndStyleCount ) ); + lItem2->setText( 0, QString::number( ++layerAndStyleCount ) ); lItem2->setText( 1, layer->style[j].name.simplified() ); lItem2->setText( 2, layer->style[j].title.simplified() ); lItem2->setText( 3, layer->style[j].abstract.simplified() ); + lItem2->setData( 0, Qt::UserRole, layer->name ); + lItem2->setData( 0, Qt::UserRole+1, layer->style[j].name ); } - } // If we got some layers, let the user add them to the map if ( lstLayers->topLevelItemCount() > 0 ) { btnAdd->setEnabled( TRUE ); + + if( lstLayers->topLevelItemCount()==1 ) + { + lstLayers->expandItem( lstLayers->topLevelItem(0) ); + } } else { @@ -360,7 +392,7 @@ { if ( m_selectedLayers.empty() == TRUE ) { - QMessageBox::information( this, tr( "Select Layer" ), tr( "You must select at least one layer first." ) ); + QMessageBox::information( this, tr( "Select Layer" ), tr( "You must select at least one leaf layer first." ) ); } else if ( mWmsProvider->supportedCrsForLayers( m_selectedLayers ).size() == 0 ) { @@ -425,7 +457,7 @@ QStringList newSelectedLayers; QStringList newSelectedStylesForSelectedLayers; - std::map newSelectedStyleIdForLayer; + QMap newSelectedStyleIdForLayer; // Iterate through the layers QList selected( lstLayers->selectedItems() ); @@ -433,20 +465,14 @@ for ( it = selected.begin(); it != selected.end(); ++it ) { QTreeWidgetItem *item = *it; - QString layerName; - if ( item->parent() != 0 ) - { - layerName = item->parent()->text( 1 ); - newSelectedStylesForSelectedLayers += item->text( 1 ); - } - else - { - layerName = item->text( 1 ); - newSelectedStylesForSelectedLayers += ""; - } + QString layerName = item->data(0, Qt::UserRole).toString(); + if( layerName.isEmpty() ) + continue; - newSelectedLayers += layerName; + newSelectedLayers << layerName; + newSelectedStylesForSelectedLayers << item->data( 0, Qt::UserRole+1 ).toString(); + newSelectedStyleIdForLayer[layerName] = item->text( 0 ); // Check if multiple styles have now been selected Index: src/providers/wms/qgswmsprovider.h =================================================================== --- src/providers/wms/qgswmsprovider.h (revision 9752) +++ src/providers/wms/qgswmsprovider.h (working copy) @@ -21,15 +21,14 @@ #ifndef QGSWMSPROVIDER_H #define QGSWMSPROVIDER_H -#include -#include - #include "qgsrasterdataprovider.h" #include "qgsrectangle.h" #include #include #include +#include +#include class QgsCoordinateTransform; @@ -78,8 +77,8 @@ // TODO: Fill to WMS specifications struct QgsWmsOperationType { - QStringList format; - std::vector dcpType; + QStringList format; + QVector dcpType; }; /** Request Property structure */ @@ -220,12 +219,12 @@ // TODO: Fill to WMS specifications struct QgsWmsStyleProperty { - QString name; - QString title; - QString abstract; - std::vector legendUrl; - QgsWmsStyleSheetUrlProperty styleSheetUrl; - QgsWmsStyleUrlProperty styleUrl; + QString name; + QString title; + QString abstract; + QVector legendUrl; + QgsWmsStyleSheetUrlProperty styleSheetUrl; + QgsWmsStyleUrlProperty styleUrl; }; /** Authority URL Property structure */ @@ -273,24 +272,25 @@ struct QgsWmsLayerProperty { // WMS layer properties - QString name; - QString title; - QString abstract; - QStringList keywordList; - std::vector crs; // coord ref sys - QgsRectangle ex_GeographicBoundingBox; - std::vector boundingBox; - std::vector dimension; - QgsWmsAttributionProperty attribution; - std::vector authorityUrl; - std::vector identifier; - std::vector metadataUrl; - std::vector dataListUrl; - std::vector featureListUrl; - std::vector style; - double minimumScaleDenominator; - double maximumScaleDenominator; - std::vector layer; // nested layers + int orderId; + QString name; + QString title; + QString abstract; + QStringList keywordList; + QVector crs; // coord ref sys + QgsRectangle ex_GeographicBoundingBox; + QVector boundingBox; + QVector dimension; + QgsWmsAttributionProperty attribution; + QVector authorityUrl; + QVector identifier; + QVector metadataUrl; + QVector dataListUrl; + QVector featureListUrl; + QVector style; + double minimumScaleDenominator; + double maximumScaleDenominator; + QVector layer; // nested layers // WMS layer attributes bool queryable; @@ -331,12 +331,9 @@ */ class QgsWmsProvider : public QgsRasterDataProvider { - Q_OBJECT public: - - /** * Constructor for the provider. * @@ -359,8 +356,13 @@ * * \todo Document this better, make static */ - virtual bool supportedLayers( std::vector & layers ); + virtual bool supportedLayers( QVector & layers ); + /** + * \brief Returns a map for the hierachy of layers + */ + virtual void layerParents( QMap &parents, QMap &parentNames ) const; + // TODO: Document this better /** \brief Returns a list of the supported CRSs of the given layers * \note Since WMS can specify CRSs per layer, this may change depending @@ -735,23 +737,23 @@ /** * layers hosted by the WMS Server */ - std::vector layersSupported; + QVector layersSupported; /** * extents per layer (in WMS CRS:84 datum) */ - std::map extentForLayer; + QMap extentForLayer; /** * available CRSs per layer */ - std::map > crsForLayer; + QMap > crsForLayer; /** * WMS "queryable" per layer * Used in determining if the Identify map tool can be useful on the rendered WMS map layer. */ - std::map mQueryableForLayer; + QMap mQueryableForLayer; /** * Active sublayers managed by this provider in a draw function, in order from bottom to top @@ -764,7 +766,7 @@ /** * Visibility status of the given active sublayer */ - std::map activeSubLayerVisibility; + QMap activeSubLayerVisibility; /** * MIME type of the image encoding used from the WMS server @@ -816,6 +818,11 @@ //! Base URL for WMS GetFeatureInfo requests QString mGetFeatureInfoUrlBase; + + int mLayerCount; + QMap mLayerParents; + QMap mLayerParentNames; + }; #endif Index: src/providers/wms/qgswmsprovider.cpp =================================================================== --- src/providers/wms/qgswmsprovider.cpp (revision 9752) +++ src/providers/wms/qgswmsprovider.cpp (working copy) @@ -59,7 +59,8 @@ cachedPixelHeight( 0 ), mCoordinateTransform( 0 ), extentDirty( TRUE ), - mGetFeatureInfoUrlBase( 0 ) + mGetFeatureInfoUrlBase( 0 ), + mLayerCount( -1 ) { QgsDebugMsg( "QgsWmsProvider: constructing with uri '" + uri + "'." ); @@ -134,7 +135,7 @@ -bool QgsWmsProvider::supportedLayers( std::vector & layers ) +bool QgsWmsProvider::supportedLayers( QVector &layers ) { QgsDebugMsg( "Entering." ); @@ -159,11 +160,11 @@ QStringList::const_iterator i; for ( i = layers.constBegin(); i != layers.constEnd(); ++i ) { - std::vector crsVector = crsForLayer[*i]; + QVector crsVector = crsForLayer[*i]; QSet crsSet; // convert std::vector to std::set for set comparisons - for ( uint j = 0; j < crsVector.size(); j++ ) + for ( int j = 0; j < crsVector.size(); j++ ) { crsSet.insert( crsVector[j] ); } @@ -192,8 +193,8 @@ } // QgsWmsProvider::layerCount() -void QgsWmsProvider::addLayers( QStringList const & layers, - QStringList const & styles ) +void QgsWmsProvider::addLayers( QStringList const &layers, + QStringList const &styles ) { QgsDebugMsg( "Entering with layer list of " + layers.join( ", " ) + " and style list of " + styles.join( ", " ) ); @@ -220,7 +221,7 @@ } -void QgsWmsProvider::setLayerOrder( QStringList const & layers ) +void QgsWmsProvider::setLayerOrder( QStringList const &layers ) { QgsDebugMsg( "Entering." ); @@ -356,7 +357,7 @@ it != activeSubLayers.end(); ++it ) { - if ( TRUE == activeSubLayerVisibility.find( *it )->second ) + if ( activeSubLayerVisibility.find( *it ).value() ) { visibleLayers += *it; visibleStyles += *it2; @@ -379,7 +380,7 @@ crsKey = "CRS"; } - std::vector dcpType = mCapabilities.capability.request.getMap.dcpType; + QVector dcpType = mCapabilities.capability.request.getMap.dcpType; if(dcpType.size() < 1) { mError = tr("Could not determine URL for GetMap from the WMS capabilities response"); @@ -849,7 +850,7 @@ QDomElement e1 = n1.toElement(); // try to convert the node to an element. if ( !e1.isNull() ) { - //QgsDebugMsg(" " + e1.tagName() ); // the node really is an element. + QgsDebugMsg(" " + e1.tagName() ); // the node really is an element. if ( e1.tagName() == "Title" ) { @@ -1308,10 +1309,7 @@ // layerProperty.title = QString::null; // layerProperty.abstract = QString::null; // layerProperty.keywordList.clear(); - - // assume true until we find a child layer - bool atleaf = TRUE; - + layerProperty.orderId = ++mLayerCount; layerProperty.queryable = e.attribute( "queryable" ).toUInt(); layerProperty.cascaded = e.attribute( "cascaded" ).toUInt(); layerProperty.opaque = e.attribute( "opaque" ).toUInt(); @@ -1325,11 +1323,11 @@ QDomElement e1 = n1.toElement(); // try to convert the node to an element. if ( !e1.isNull() ) { - //QgsDebugMsg(" " + e1.tagName() ); // the node really is an element. + QgsDebugMsg(" " + e1.tagName() ); // the node really is an element. if ( e1.tagName() == "Layer" ) { -// QgsDebugMsg(" Nested layer."); + QgsDebugMsg(" Nested layer."); QgsWmsLayerProperty subLayerProperty; @@ -1344,8 +1342,6 @@ parseLayer( e1, subLayerProperty, &layerProperty ); layerProperty.layer.push_back( subLayerProperty ); - - atleaf = FALSE; } else if ( e1.tagName() == "Name" ) { @@ -1474,8 +1470,13 @@ n1 = n1.nextSibling(); } - if ( atleaf ) + if(parentProperty) { + mLayerParents[ layerProperty.orderId ] = parentProperty->orderId; + } + + if ( layerProperty.layer.empty() ) + { // We have all the information we need to properly evaluate a layer definition // TODO: Save this somewhere @@ -1493,7 +1494,7 @@ extentForLayer[ layerProperty.name ] = layerProperty.ex_GeographicBoundingBox; // see if we can refine the bounding box with the CRS-specific bounding boxes - for ( uint i = 0; i < layerProperty.boundingBox.size(); i++ ) + for ( int i = 0; i < layerProperty.boundingBox.size(); i++ ) { QgsDebugMsg( "testing bounding box CRS which is " + layerProperty.boundingBox[i].crs + "." ); @@ -1513,15 +1514,24 @@ layersSupported.push_back( layerProperty ); //if there are several elements without a parent layer, the style list needs to be cleared - if ( atleaf ) + if ( layerProperty.layer.empty() ) { layerProperty.style.clear(); } } + else + { + mLayerParentNames[ layerProperty.orderId ] = QStringList() << layerProperty.name << layerProperty.title << layerProperty.abstract; + } // QgsDebugMsg("exiting."); } +void QgsWmsProvider::layerParents( QMap &parents, QMap &parentNames ) const +{ + parents = mLayerParents; + parentNames = mLayerParentNames; +} bool QgsWmsProvider::parseServiceExceptionReportDom( QByteArray const & xml ) { @@ -1749,7 +1759,7 @@ { QgsDebugMsg( "Sublayer Iterator: " + *it ); // This is the extent for the layer name in *it - QgsRectangle extent = extentForLayer.find( *it )->second; + QgsRectangle extent = extentForLayer.find( *it ).value(); // Convert to the user's CRS as required try @@ -1805,10 +1815,10 @@ ++it ) { // Is sublayer visible? - if ( TRUE == activeSubLayerVisibility.find( *it )->second ) + if ( activeSubLayerVisibility.find( *it ).value() ) { // Is sublayer queryable? - if ( TRUE == mQueryableForLayer.find( *it )->second ) + if ( mQueryableForLayer.find( *it ).value() ) { QgsDebugMsg( "'" + ( *it ) + "' is queryable." ); canIdentify = TRUE; @@ -1948,7 +1958,7 @@ // Iterate through layers - for ( uint i = 0; i < layersSupported.size(); i++ ) + for ( int i = 0; i < layersSupported.size(); i++ ) { // TODO: Handle nested layers @@ -1988,7 +1998,7 @@ myMetadataQString += ""; myMetadataQString += ( activeSubLayers.indexOf( layerName ) >= 0 ) ? ( - ( activeSubLayerVisibility.find( layerName )->second ) ? + ( activeSubLayerVisibility.find( layerName ).value() ) ? tr( "Visible" ) : tr( "Hidden" ) ) : tr( "n/a" ); @@ -2067,7 +2077,7 @@ myMetadataQString += ""; // Layer Coordinate Reference Systems - for ( uint j = 0; j < layersSupported[i].crs.size(); j++ ) + for ( int j = 0; j < layersSupported[i].crs.size(); j++ ) { myMetadataQString += ""; myMetadataQString += tr( "Available in CRS" ); @@ -2078,7 +2088,7 @@ } // Layer Styles - for ( uint j = 0; j < layersSupported[i].style.size(); j++ ) + for ( int j = 0; j < layersSupported[i].style.size(); j++ ) { myMetadataQString += ""; myMetadataQString += tr( "Available in style" ); @@ -2145,10 +2155,10 @@ ++it ) { // Is sublayer visible? - if ( TRUE == activeSubLayerVisibility.find( *it )->second ) + if ( activeSubLayerVisibility.find( *it ).value() ) { // Is sublayer queryable? - if ( TRUE == mQueryableForLayer.find( *it )->second ) + if ( mQueryableForLayer.find( *it ).value() ) { QgsDebugMsg( "Layer '" + *it + "' is queryable." ); // Compose request to WMS server