void QgsDatumTransformDialog::updateTitle()
{
  mLabelLayer->setText( mLayerName );
  QgsCoordinateReferenceSystem crs;
  crs.createFromString( mSrcCRSauthId );
  mLabelSrcCrs->setText( QString( "%1 - %2" ).arg( mSrcCRSauthId, crs.isValid() ? crs.description() : tr( "unknown" ) ) );
  crs.createFromString( mDestCRSauthId );
  mLabelDstCrs->setText( QString( "%1 - %2" ).arg( mDestCRSauthId, crs.isValid() ? crs.description() : tr( "unknown" ) ) );
}
void QgsProjectionSelectionWidget::addRecentCrs()
{
  QStringList recentProjections = QgsCoordinateReferenceSystem::recentProjections();
  int i = 0;
  Q_FOREACH ( const QString& projection, recentProjections )
  {
    long srsid = projection.toLong();

    //check if already shown
    if ( crsIsShown( srsid ) )
    {
      continue;
    }

    i++;
    QgsCoordinateReferenceSystem crs;
    crs.createFromSrsId( srsid );
    if ( crs.isValid() )
    {
      mCrsComboBox->addItem( tr( "%1 - %2" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::RecentCrs );
      mCrsComboBox->setItemData( mCrsComboBox->count() - 1, QVariant(( long long )srsid ), Qt::UserRole + 1 );
    }
    if ( i >= 4 )
    {
      //limit to 4 recent projections to avoid clutter
      break;
    }
  }
QString QgsProjectionSelectionWidget::crsOptionText( const QgsCoordinateReferenceSystem &crs )
{
  if ( crs.isValid() )
    return tr( "%1 - %2" ).arg( crs.authid(), crs.description() );
  else
    return tr( "invalid projection" );
}
bool QgsCoordinateTransform::datumTransformCrsInfo( int datumTransform, int& epsgNr, QString& srcProjection, QString& dstProjection, QString &remarks, QString &scope, bool &preferred, bool &deprecated )
{
    sqlite3* db;
    int openResult = sqlite3_open( QgsApplication::srsDbFilePath().toUtf8().constData(), &db );
    if ( openResult != SQLITE_OK )
    {
        sqlite3_close( db );
        return false;
    }

    sqlite3_stmt* stmt;
    QString sql = QString( "SELECT epsg_nr,source_crs_code,target_crs_code,remarks,scope,preferred,deprecated FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
    int prepareRes = sqlite3_prepare( db, sql.toAscii(), sql.size(), &stmt, NULL );
    if ( prepareRes != SQLITE_OK )
    {
        sqlite3_finalize( stmt );
        sqlite3_close( db );
        return false;
    }

    int srcCrsId, destCrsId;
    if ( sqlite3_step( stmt ) != SQLITE_ROW )
    {
        sqlite3_finalize( stmt );
        sqlite3_close( db );
        return false;
    }

    epsgNr = sqlite3_column_int( stmt, 0 );
    srcCrsId = sqlite3_column_int( stmt, 1 );
    destCrsId = sqlite3_column_int( stmt, 2 );
    remarks = QString::fromUtf8(( const char * ) sqlite3_column_text( stmt, 3 ) );
    scope = QString::fromUtf8(( const char * ) sqlite3_column_text( stmt, 4 ) );
    preferred = sqlite3_column_int( stmt, 5 ) != 0;
    deprecated = sqlite3_column_int( stmt, 6 ) != 0;

    QgsCoordinateReferenceSystem srcCrs;
    srcCrs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( srcCrsId ) );
    srcProjection = srcCrs.description();
    QgsCoordinateReferenceSystem destCrs;
    destCrs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( destCrsId ) );
    dstProjection = destCrs.description();

    sqlite3_finalize( stmt );
    sqlite3_close( db );
    return true;
}
void QgsNewSpatialiteLayerDialog::pbnFindSRID_clicked()
{
  // first get list of supported SRID from the selected SpatiaLite database
  // to build filter for projection selector
  sqlite3_database_unique_ptr database;
  bool status = true;
  int rc = database.open_v2( mDatabaseComboBox->currentText(), SQLITE_OPEN_READONLY, nullptr );
  if ( rc != SQLITE_OK )
  {
    QMessageBox::warning( this, tr( "SpatiaLite Database" ), tr( "Unable to open the database" ) );
    return;
  }

  // load up the srid table
  sqlite3_statement_unique_ptr statement;
  QString sql = QStringLiteral( "select auth_name || ':' || auth_srid from spatial_ref_sys order by srid asc" );

  QSet<QString> myCRSs;

  statement = database.prepare( sql, rc );
  // XXX Need to free memory from the error msg if one is set
  if ( rc == SQLITE_OK )
  {
    // get the first row of the result set
    while ( sqlite3_step( statement.get() ) == SQLITE_ROW )
    {
      myCRSs.insert( statement.columnAsText( 0 ) );
    }
  }
  else
  {
    // XXX query failed -- warn the user some how
    QMessageBox::warning( nullptr, tr( "Error" ), tr( "Failed to load SRIDS: %1" ).arg( database.errorMessage() ) );
    status = false;
  }

  if ( status )
  {
    // prepare projection selector
    QgsProjectionSelectionDialog *mySelector = new QgsProjectionSelectionDialog( this );
    mySelector->setMessage( QString() );
    mySelector->setOgcWmsCrsFilter( myCRSs );
    mySelector->setCrs( QgsCoordinateReferenceSystem::fromOgcWmsCrs( mCrsId ) );

    if ( mySelector->exec() )
    {
      QgsCoordinateReferenceSystem srs = mySelector->crs();
      QString crsId = srs.authid();
      if ( crsId != mCrsId )
      {
        mCrsId = crsId;
        leSRID->setText( srs.authid() + " - " + srs.description() );
      }
    }
    delete mySelector;
  }
}
bool QgsCoordinateTransform::datumTransformCrsInfo( int datumTransform, int &epsgNr, QString &srcProjection, QString &dstProjection, QString &remarks, QString &scope, bool &preferred, bool &deprecated )
{
  sqlite3_database_unique_ptr database;
  int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
  if ( openResult != SQLITE_OK )
  {
    return false;
  }

  sqlite3_statement_unique_ptr statement;
  QString sql = QStringLiteral( "SELECT epsg_nr,source_crs_code,target_crs_code,remarks,scope,preferred,deprecated FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
  int prepareRes;
  statement = database.prepare( sql, prepareRes );
  if ( prepareRes != SQLITE_OK )
  {
    return false;
  }

  int srcCrsId, destCrsId;
  if ( statement.step() != SQLITE_ROW )
  {
    return false;
  }

  epsgNr = statement.columnAsInt64( 0 );
  srcCrsId = statement.columnAsInt64( 1 );
  destCrsId = statement.columnAsInt64( 2 );
  remarks = statement.columnAsText( 3 );
  scope = statement.columnAsText( 4 );
  preferred = statement.columnAsInt64( 5 ) != 0;
  deprecated = statement.columnAsInt64( 6 ) != 0;

  QgsCoordinateReferenceSystem srcCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( srcCrsId ) );
  srcProjection = srcCrs.description();
  QgsCoordinateReferenceSystem destCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( destCrsId ) );
  dstProjection = destCrs.description();

  return true;
}
QgsNewSpatialiteLayerDialog::QgsNewSpatialiteLayerDialog( QWidget *parent, Qt::WindowFlags fl )
    : QDialog( parent, fl )
{
  setupUi( this );

  QSettings settings;
  restoreGeometry( settings.value( "/Windows/NewSpatiaLiteLayer/geometry" ).toByteArray() );

  mAddAttributeButton->setIcon( QgsApplication::getThemeIcon( "/mActionNewAttribute.png" ) );
  mRemoveAttributeButton->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.png" ) );
  mTypeBox->addItem( tr( "Text data" ), "text" );
  mTypeBox->addItem( tr( "Whole number" ), "integer" );
  mTypeBox->addItem( tr( "Decimal number" ), "real" );

  mPointRadioButton->setChecked( true );
  // Populate the database list from the stored connections
  settings.beginGroup( "/SpatiaLite/connections" );
  QStringList keys = settings.childGroups();
  QStringList::Iterator it = keys.begin();
  mDatabaseComboBox->clear();
  while ( it != keys.end() )
  {
    // retrieving the SQLite DB name and full path
    QString text = settings.value( *it + "/sqlitepath", "###unknown###" ).toString();
    mDatabaseComboBox->addItem( text );
    ++it;
  }
  settings.endGroup();

  mOkButton = buttonBox->button( QDialogButtonBox::Ok );
  mOkButton->setEnabled( false );

  // Set the SRID box to a default of WGS84
  QgsCoordinateReferenceSystem srs;
  srs.createFromOgcWmsCrs( settings.value( "/Projections/layerDefaultCrs", GEO_EPSG_CRS_AUTHID ).toString() );
  srs.validate();
  mCrsId = srs.authid();
  leSRID->setText( srs.authid() + " - " + srs.description() );

  pbnFindSRID->setEnabled( mDatabaseComboBox->count() );

  connect( mNameEdit, SIGNAL( textChanged( QString ) ), this, SLOT( nameChanged( QString ) ) );
  connect( mAttributeView, SIGNAL( itemSelectionChanged() ), this, SLOT( selectionChanged() ) );
  connect( leLayerName, SIGNAL( textChanged( const QString& text ) ), this, SLOT( checkOk() ) );
  connect( checkBoxPrimaryKey, SIGNAL( clicked() ), this, SLOT( checkOk() ) );

  mAddAttributeButton->setEnabled( false );
  mRemoveAttributeButton->setEnabled( false );

}
void QgsProjectionSelectionWidget::setCrs( const QgsCoordinateReferenceSystem& crs )
{
  if ( crs.isValid() )
  {
    mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
                               tr( "Selected CRS (%1, %2)" ).arg( crs.authid(), crs.description() ) );
    mCrsComboBox->blockSignals( true );
    mCrsComboBox->setCurrentIndex( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ) );
    mCrsComboBox->blockSignals( false );
  }
  else
  {
    mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
                               tr( "invalid projection" ) );
  }
  mCrs = crs;
}
void QgsNewVectorLayerDialog::on_pbnChangeSpatialRefSys_clicked()
{
  QgsGenericProjectionSelector *mySelector = new QgsGenericProjectionSelector( this );
  mySelector->setMessage();
  mySelector->setSelectedCrsId( mCrsId );
  if ( mySelector->exec() )
  {
    QgsCoordinateReferenceSystem srs;
    srs.createFromOgcWmsCrs( mySelector->selectedAuthId() );
    mCrsId = srs.srsid();
    leSpatialRefSys->setText( srs.authid() + " - " + srs.description() );
  }
  else
  {
    QApplication::restoreOverrideCursor();
  }
  delete mySelector;
}
void QgsNewSpatialiteLayerDialog::on_pbnFindSRID_clicked()
{
    // first get list of supported SRID from the selected Spatialite database
    // to build filter for projection selector
    sqlite3 *db = 0;
    bool status = true;
    int rc = sqlite3_open_v2( mDatabaseComboBox->currentText().toUtf8(), &db, SQLITE_OPEN_READONLY, NULL );
    if ( rc != SQLITE_OK )
    {
        QMessageBox::warning( this, tr( "SpatiaLite Database" ), tr( "Unable to open the database" ) );
        return;
    }

    // load up the srid table
    const char *pzTail;
    sqlite3_stmt *ppStmt;
    QString sql = "select auth_name || ':' || auth_srid from spatial_ref_sys order by srid asc";

    QSet<QString> myCRSs;

    rc = sqlite3_prepare( db, sql.toUtf8(), sql.toUtf8().length(), &ppStmt, &pzTail );
    // XXX Need to free memory from the error msg if one is set
    if ( rc == SQLITE_OK )
    {
        // get the first row of the result set
        while ( sqlite3_step( ppStmt ) == SQLITE_ROW )
        {
            myCRSs.insert( QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 0 ) ) );
        }
    }
    else
    {
        // XXX query failed -- warn the user some how
        QMessageBox::warning( 0, tr( "Error" ), tr( "Failed to load SRIDS: %1" ).arg( sqlite3_errmsg( db ) ) );
        status = false;
    }
    // close the statement
    sqlite3_finalize( ppStmt );
    sqlite3_close( db );

    if ( !status )
    {
        return;
    }

    // prepare projection selector
    QgsGenericProjectionSelector *mySelector = new QgsGenericProjectionSelector( this );
    mySelector->setMessage();
    mySelector->setOgcWmsCrsFilter( myCRSs );
    mySelector->setSelectedAuthId( mCrsId );

    if ( mySelector->exec() )
    {
        QgsCoordinateReferenceSystem srs;
        srs.createFromOgcWmsCrs( mySelector->selectedAuthId() );
        QString crsId = srs.authid();
        if ( crsId != mCrsId )
        {
            mCrsId = crsId;
            leSRID->setText( srs.authid() + " - " + srs.description() );
        }
    }
    delete mySelector;
}
void QgsProjectionSelectionWidget::setLayerCrs( const QgsCoordinateReferenceSystem &crs )
{
  int layerItemIndex = mCrsComboBox->findData( QgsProjectionSelectionWidget::LayerCrs );
  if ( crs.isValid() )
  {
    if ( layerItemIndex > -1 )
    {
      mCrsComboBox->setItemText( layerItemIndex, tr( "Layer CRS (%1, %2)" ).arg( crs.authid(), crs.description() ) );
    }
    else
    {
      mCrsComboBox->insertItem( firstRecentCrsIndex(), tr( "Layer CRS (%1, %2)" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::LayerCrs );
    }
  }
  else
  {
    if ( layerItemIndex > -1 )
    {
      mCrsComboBox->removeItem( layerItemIndex );
    }
  }
  mLayerCrs = crs;
}
QgsNewSpatialiteLayerDialog::QgsNewSpatialiteLayerDialog( QWidget *parent, Qt::WindowFlags fl, const QgsCoordinateReferenceSystem &defaultCrs )
  : QDialog( parent, fl )
{
  setupUi( this );
  connect( mAddAttributeButton, &QToolButton::clicked, this, &QgsNewSpatialiteLayerDialog::mAddAttributeButton_clicked );
  connect( mRemoveAttributeButton, &QToolButton::clicked, this, &QgsNewSpatialiteLayerDialog::mRemoveAttributeButton_clicked );
  connect( mTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewSpatialiteLayerDialog::mTypeBox_currentIndexChanged );
  connect( pbnFindSRID, &QPushButton::clicked, this, &QgsNewSpatialiteLayerDialog::pbnFindSRID_clicked );
  connect( toolButtonNewDatabase, &QToolButton::clicked, this, &QgsNewSpatialiteLayerDialog::toolButtonNewDatabase_clicked );
  connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsNewSpatialiteLayerDialog::buttonBox_accepted );
  connect( buttonBox, &QDialogButtonBox::rejected, this, &QgsNewSpatialiteLayerDialog::buttonBox_rejected );

  QgsSettings settings;
  restoreGeometry( settings.value( QStringLiteral( "Windows/NewSpatiaLiteLayer/geometry" ) ).toByteArray() );

  mGeometryTypeBox->addItem( tr( "Point" ), QStringLiteral( "POINT" ) );
  mGeometryTypeBox->addItem( tr( "Line" ), QStringLiteral( "LINE" ) );
  mGeometryTypeBox->addItem( tr( "Polygon" ), QStringLiteral( "POLYGON" ) );
  mGeometryTypeBox->addItem( tr( "MultiPoint" ), QStringLiteral( "MULTIPOINT" ) );
  mGeometryTypeBox->addItem( tr( "MultiLine" ), QStringLiteral( "MULTILINE" ) );
  mGeometryTypeBox->addItem( tr( "MultiPolygon" ), QStringLiteral( "MULTIPOLYGON" ) );

  mAddAttributeButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewAttribute.svg" ) ) );
  mRemoveAttributeButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteAttribute.svg" ) ) );
  mTypeBox->addItem( tr( "Text data" ), "text" );
  mTypeBox->addItem( tr( "Whole number" ), "integer" );
  mTypeBox->addItem( tr( "Decimal number" ), "real" );

  // Populate the database list from the stored connections
  settings.beginGroup( QStringLiteral( "SpatiaLite/connections" ) );
  QStringList keys = settings.childGroups();
  QStringList::Iterator it = keys.begin();
  mDatabaseComboBox->clear();
  while ( it != keys.end() )
  {
    // retrieving the SQLite DB name and full path
    QString text = settings.value( *it + "/sqlitepath", "###unknown###" ).toString();
    mDatabaseComboBox->addItem( text );
    ++it;
  }
  settings.endGroup();

  mOkButton = buttonBox->button( QDialogButtonBox::Ok );
  mOkButton->setEnabled( false );

  // Set the SRID box to a default of WGS84
  mCrsId = defaultCrs.authid();
  leSRID->setText( defaultCrs.authid() + " - " + defaultCrs.description() );

  pbnFindSRID->setEnabled( mDatabaseComboBox->count() );

  connect( mNameEdit, &QLineEdit::textChanged, this, &QgsNewSpatialiteLayerDialog::nameChanged );
  connect( mAttributeView, &QTreeWidget::itemSelectionChanged, this, &QgsNewSpatialiteLayerDialog::selectionChanged );
  connect( leLayerName, &QLineEdit::textChanged, this, &QgsNewSpatialiteLayerDialog::checkOk );
  connect( checkBoxPrimaryKey, &QAbstractButton::clicked, this, &QgsNewSpatialiteLayerDialog::checkOk );

  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsNewSpatialiteLayerDialog::showHelp );

  mAddAttributeButton->setEnabled( false );
  mRemoveAttributeButton->setEnabled( false );

}
QgsNewVectorLayerDialog::QgsNewVectorLayerDialog( QWidget *parent, Qt::WindowFlags fl )
    : QDialog( parent, fl )
{
  setupUi( this );

  QSettings settings;
  restoreGeometry( settings.value( "/Windows/NewVectorLayer/geometry" ).toByteArray() );

  mAddAttributeButton->setIcon( QgsApplication::getThemeIcon( "/mActionNewAttribute.png" ) );
  mRemoveAttributeButton->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteAttribute.png" ) );
  mTypeBox->addItem( tr( "Text data" ), "String" );
  mTypeBox->addItem( tr( "Whole number" ), "Integer" );
  mTypeBox->addItem( tr( "Decimal number" ), "Real" );
  mTypeBox->addItem( tr( "Date" ), "Date" );

  mWidth->setValidator( new QIntValidator( 1, 255, this ) );
  mPrecision->setValidator( new QIntValidator( 0, 15, this ) );

  mPointRadioButton->setChecked( true );
  mFileFormatComboBox->addItem( tr( "ESRI Shapefile" ), "ESRI Shapefile" );
#if 0
  // Disabled until provider properly supports editing the created file formats
  mFileFormatComboBox->addItem( tr( "Comma Separated Value" ), "Comma Separated Value" );
  mFileFormatComboBox->addItem( tr( "GML" ), "GML" );
  mFileFormatComboBox->addItem( tr( "Mapinfo File" ), "Mapinfo File" );
#endif
  if ( mFileFormatComboBox->count() == 1 )
  {
    mFileFormatComboBox->setVisible( false );
    mFileFormatLabel->setVisible( false );
  }

  mFileFormatComboBox->setCurrentIndex( 0 );

  mFileEncoding->addItems( QgsVectorDataProvider::availableEncodings() );

  // Use default encoding if none supplied
  QString enc = QSettings().value( "/UI/encoding", "System" ).toString();

  // The specified decoding is added if not existing alread, and then set current.
  // This should select it.
  int encindex = mFileEncoding->findText( enc );
  if ( encindex < 0 )
  {
    mFileEncoding->insertItem( 0, enc );
    encindex = 0;
  }
  mFileEncoding->setCurrentIndex( encindex );

  mOkButton = buttonBox->button( QDialogButtonBox::Ok );

  mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << "id" << "Integer" << "10" << "" ) );

  QgsCoordinateReferenceSystem srs;

  srs.createFromOgcWmsCrs( settings.value( "/Projections/layerDefaultCrs", GEO_EPSG_CRS_AUTHID ).toString() );
  srs.validate();

  mCrsId = srs.srsid();
  leSpatialRefSys->setText( srs.authid() + " - " + srs.description() );

  connect( mNameEdit, SIGNAL( textChanged( QString ) ), this, SLOT( nameChanged( QString ) ) );
  connect( mAttributeView, SIGNAL( itemSelectionChanged() ), this, SLOT( selectionChanged() ) );

  mAddAttributeButton->setEnabled( false );
  mRemoveAttributeButton->setEnabled( false );
}
Exemple #14
0
// ------------------------ 1.1 ----------------------------------------------
bool QgsWcsCapabilities::parseDescribeCoverageDom11( 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 != QLatin1String( "CoverageDescriptions" ) )
  {
    mErrorTitle = tr( "Dom Exception" );
    mErrorFormat = QStringLiteral( "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( QStringLiteral( "CoverageDescriptions" ),
                   docElem.tagName(),
                   QString( xml ) );

    QgsLogger::debug( "Dom Exception: " + mError );

    return false;
  }

  // Get image size, we can get it from BoundingBox with crs=urn:ogc:def:crs:OGC::imageCRS
  // but while at least one BoundingBox is mandatory, it does not have to be urn:ogc:def:crs:OGC::imageCRS
  // TODO: if BoundingBox with crs=urn:ogc:def:crs:OGC::imageCRS is not found,
  // we could calculate image size from GridCRS.GridOffsets (if available)
  QList<QDomElement> boundingBoxElements = domElements( docElem, QStringLiteral( "CoverageDescription.Domain.SpatialDomain.BoundingBox" ) );

  QgsDebugMsg( QStringLiteral( "%1 BoundingBox found" ).arg( boundingBoxElements.size() ) );

  const auto constBoundingBoxElements = boundingBoxElements;
  for ( const QDomElement &el : constBoundingBoxElements )
  {
    QString authid = crsUrnToAuthId( el.attribute( QStringLiteral( "crs" ) ) );
    QList<double> low = parseDoubles( domElementText( el, QStringLiteral( "LowerCorner" ) ) );
    QList<double> high = parseDoubles( domElementText( el, QStringLiteral( "UpperCorner" ) ) );

    if ( low.size() != 2 && high.size() != 2 ) continue;

    if ( el.attribute( QStringLiteral( "crs" ) ) == QLatin1String( "urn:ogc:def:crs:OGC::imageCRS" ) )
    {
      coverage->width = ( int )( high[0] - low[0] + 1 );
      coverage->height = ( int )( high[1] - low[1] + 1 );
      coverage->hasSize = true;
    }
    else
    {
      QgsRectangle box;
      QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( authid );
      if ( crs.isValid() && crs.hasAxisInverted() )
      {
        box = QgsRectangle( low[1], low[0], high[1], high[0] );
      }
      else
      {
        box = QgsRectangle( low[0], low[1], high[0], high[1] );
      }
      coverage->boundingBoxes.insert( authid, box );
      QgsDebugMsg( "crs: " + crs.authid() + ' ' + crs.description() + QString( " axisInverted = %1" ).arg( crs.hasAxisInverted() ) );
      QgsDebugMsg( "BoundingBox: " + authid + " : " + box.toString() );
    }
  }
  QgsDebugMsg( QStringLiteral( "width = %1 height = %2" ).arg( coverage->width ).arg( coverage->height ) );

  // Each georectified coverage should have GridCRS
  QDomElement gridCRSElement = domElement( docElem, QStringLiteral( "CoverageDescription.Domain.SpatialDomain.GridCRS" ) );

  if ( !gridCRSElement.isNull() )
  {
    QString crsUrn = firstChildText( gridCRSElement, QStringLiteral( "GridBaseCRS" ) );
    coverage->nativeCrs = crsUrnToAuthId( crsUrn );
    QgsDebugMsg( "nativeCrs = " + coverage->nativeCrs );

    // TODO: consider getting coverage size from GridOffsets (resolution)
    // if urn:ogc:def:crs:OGC::imageCRS BoundingBox was not found
  }

  coverage->times = domElementsTexts( docElem, QStringLiteral( "CoverageDescription.Domain.TemporalDomain.timePosition" ) );

  QList<QDomElement> timePeriodElements = domElements( docElem, QStringLiteral( "CoverageDescription.Domain.TemporalDomain.timePeriod" ) );

  QgsDebugMsg( QStringLiteral( "%1 timePeriod found" ).arg( timePeriodElements.size() ) );

  const auto constTimePeriodElements = timePeriodElements;
  for ( const QDomElement &el : constTimePeriodElements )
  {
    QString beginPosition = domElementText( el, QStringLiteral( "beginTime" ) );
    QString endPosition = domElementText( el, QStringLiteral( "endTime" ) );
    QString timeResolution = domElementText( el, QStringLiteral( "timeResolution" ) );
    // Format used in request
    QString time = beginPosition + '/' + endPosition;
    if ( !timeResolution.isEmpty() )
    {
      time += '/' + timeResolution;
    }
    coverage->times << time;
  }

  // NULL / no data values
  // TODO: handle multiple fields / ranges (?)
  Q_FOREACH ( const QString &text, domElementsTexts( docElem, "CoverageDescription.Range.Field.NullValue" ) )
  {
    bool ok;
    double val = text.toDouble( &ok );
    if ( ok )
    {
      coverage->nullValues.append( val );
    }
  }

  QStringList formats = domElementsTexts( docElem, QStringLiteral( "CoverageDescription.SupportedFormat" ) );
  // There could be formats from GetCapabilities
  if ( !formats.isEmpty() )
  {
    coverage->supportedFormat = formats;
  }


  QStringList crss = domElementsTexts( docElem, QStringLiteral( "CoverageDescription.SupportedCRS" ) );
  QSet<QString> authids; // Set, in case one CRS is in more formats (URN, non URN)
  const auto constCrss = crss;
  for ( const QString &crs : constCrss )
  {
    authids.insert( crsUrnToAuthId( crs ) );
  }
  if ( !authids.isEmpty() )
  {
    coverage->supportedCrs = authids.toList();
  }

  coverage->described = true;

  return true;
}