diff --git a/src/core/stac/qgsstaccontroller.cpp b/src/core/stac/qgsstaccontroller.cpp index 1a246fc47c7..0bd7718cd36 100644 --- a/src/core/stac/qgsstaccontroller.cpp +++ b/src/core/stac/qgsstaccontroller.cpp @@ -104,7 +104,7 @@ void QgsStacController::handleStacObjectReply() parser.setData( data ); parser.setBaseUrl( reply->url() ); - QgsStacObject *object = nullptr; + std::unique_ptr< QgsStacObject > object; switch ( parser.type() ) { case QgsStacObject::Type::Catalog: @@ -120,7 +120,7 @@ void QgsStacController::handleStacObjectReply() object = nullptr; break; } - mFetchedStacObjects.insert( requestId, object ); + mFetchedStacObjects.insert( requestId, object.release() ); emit finishedStacObjectRequest( requestId, parser.error() ); reply->deleteLater(); mReplies.removeOne( reply ); @@ -148,18 +148,29 @@ void QgsStacController::handleItemCollectionReply() parser.setData( data ); parser.setBaseUrl( reply->url() ); - QgsStacItemCollection *fc = parser.itemCollection(); - mFetchedItemCollections.insert( requestId, fc ); + std::unique_ptr fc = parser.itemCollection(); + mFetchedItemCollections.insert( requestId, fc.release() ); emit finishedItemCollectionRequest( requestId, parser.error() ); reply->deleteLater(); mReplies.removeOne( reply ); } -std::unique_ptr< QgsStacObject > QgsStacController::takeStacObject( int requestId ) +template +std::unique_ptr QgsStacController::takeStacObject( int requestId ) { std::unique_ptr< QgsStacObject > obj( mFetchedStacObjects.take( requestId ) ); - return obj; + + if ( T *downCastObj = dynamic_cast< T * >( obj.get() ) ) + { + ( void )obj.release(); + return std::unique_ptr< T >( downCastObj ); + } + + return nullptr; } +template CORE_EXPORT std::unique_ptr< QgsStacItem > QgsStacController::takeStacObject( int requestId ); +template CORE_EXPORT std::unique_ptr< QgsStacCatalog > QgsStacController::takeStacObject( int requestId ); +template CORE_EXPORT std::unique_ptr< QgsStacObject > QgsStacController::takeStacObject( int requestId ); std::unique_ptr< QgsStacItemCollection > QgsStacController::takeItemCollection( int requestId ) { @@ -167,45 +178,6 @@ std::unique_ptr< QgsStacItemCollection > QgsStacController::takeItemCollection( return col; } -std::unique_ptr< QgsStacObject > QgsStacController::fetchStacObject( const QUrl &url, QString *error ) -{ - QgsNetworkReplyContent content = fetchBlocking( url ); - - if ( content.error() != QNetworkReply::NoError ) - { - if ( error ) - *error = content.errorString(); - - return nullptr; - } - - const QByteArray data = content.content(); - - QgsStacParser parser; - parser.setData( data ); - parser.setBaseUrl( url ); - std::unique_ptr< QgsStacObject > object; - switch ( parser.type() ) - { - case QgsStacObject::Type::Catalog: - object.reset( parser.catalog() ); - break; - case QgsStacObject::Type::Collection: - object.reset( parser.collection() ); - break; - case QgsStacObject::Type::Item: - object.reset( parser.item() ); - break; - case QgsStacObject::Type::Unknown: - break; - } - - if ( error ) - *error = parser.error(); - - return object; -} - std::unique_ptr< QgsStacItemCollection > QgsStacController::fetchItemCollection( const QUrl &url, QString *error ) { QgsNetworkReplyContent content = fetchBlocking( url ); @@ -283,7 +255,7 @@ void QgsStacController::setAuthCfg( const QString &authCfg ) mAuthCfg = authCfg; } -QgsStacCatalog *QgsStacController::openLocalCatalog( const QString &fileName ) const +std::unique_ptr QgsStacController::openLocalCatalog( const QString &fileName ) const { QFile file( fileName ); const bool ok = file.open( QIODevice::ReadOnly ); @@ -300,7 +272,7 @@ QgsStacCatalog *QgsStacController::openLocalCatalog( const QString &fileName ) c } -QgsStacCollection *QgsStacController::openLocalCollection( const QString &fileName ) const +std::unique_ptr QgsStacController::openLocalCollection( const QString &fileName ) const { QFile file( fileName ); const bool ok = file.open( QIODevice::ReadOnly ); @@ -316,7 +288,7 @@ QgsStacCollection *QgsStacController::openLocalCollection( const QString &fileNa return parser.collection(); } -QgsStacItem *QgsStacController::openLocalItem( const QString &fileName ) const +std::unique_ptr QgsStacController::openLocalItem( const QString &fileName ) const { QFile file( fileName ); const bool ok = file.open( QIODevice::ReadOnly ); @@ -331,3 +303,58 @@ QgsStacItem *QgsStacController::openLocalItem( const QString &fileName ) const parser.setBaseUrl( fileName ); return parser.item(); } + +template +std::unique_ptr QgsStacController::fetchStacObject( const QUrl &url, QString *error ) +{ + QgsNetworkReplyContent content = fetchBlocking( url ); + + if ( content.error() != QNetworkReply::NoError ) + { + if ( error ) + *error = content.errorString(); + + return nullptr; + } + + const QByteArray data = content.content(); + + QgsStacParser parser; + parser.setData( data ); + parser.setBaseUrl( url ); + std::unique_ptr< QgsStacObject > object; + switch ( parser.type() ) + { + case QgsStacObject::Type::Catalog: + object = parser.catalog(); + break; + case QgsStacObject::Type::Collection: + object = parser.collection(); + break; + case QgsStacObject::Type::Item: + object = parser.item(); + break; + case QgsStacObject::Type::Unknown: + break; + } + + std::unique_ptr< T > res; + if ( T *castObject = dynamic_cast< T * >( object.get() ) ) + { + ( void )object.release(); + res.reset( castObject ); + } + else + { + QgsDebugError( "Retrieved STAC object could not be cast to expected type" ); + } + + if ( error ) + *error = parser.error(); + + return res; +} + +template CORE_EXPORT std::unique_ptr< QgsStacItem > QgsStacController::fetchStacObject( const QUrl &url, QString *error ); +template CORE_EXPORT std::unique_ptr< QgsStacCollection > QgsStacController::fetchStacObject( const QUrl &url, QString *error ); +template CORE_EXPORT std::unique_ptr< QgsStacCatalog > QgsStacController::fetchStacObject( const QUrl &url, QString *error ); diff --git a/src/core/stac/qgsstaccontroller.h b/src/core/stac/qgsstaccontroller.h index dbde72c4cd0..71c9048aea0 100644 --- a/src/core/stac/qgsstaccontroller.h +++ b/src/core/stac/qgsstaccontroller.h @@ -24,6 +24,7 @@ #include "qgis_core.h" #include "qgshttpheaders.h" #include "qgsnetworkreply.h" +#include "qgsstacobject.h" class QgsStacObject; class QgsStacCatalog; @@ -56,26 +57,26 @@ class CORE_EXPORT QgsStacController : public QObject * Returns a STAC Catalog by parsing a local file * The caller takes ownership of the returned catalog */ - QgsStacCatalog *openLocalCatalog( const QString &fileName ) const; + std::unique_ptr< QgsStacCatalog > openLocalCatalog( const QString &fileName ) const; /** * Returns a STAC Collection by parsing a local file * The caller takes ownership of the returned collection */ - QgsStacCollection *openLocalCollection( const QString &fileName ) const; + std::unique_ptr< QgsStacCollection > openLocalCollection( const QString &fileName ) const; /** * Returns a STAC Item by parsing a local file * The caller takes ownership of the returned item */ - QgsStacItem *openLocalItem( const QString &fileName ) const; + std::unique_ptr< QgsStacItem > openLocalItem( const QString &fileName ) const; /** * Fetches a STAC object from \a url using a blocking network request. * An optional \a error parameter will be populated with any network error information. * The caller takes ownership of the returned object */ - std::unique_ptr< QgsStacObject > fetchStacObject( const QUrl &url, QString *error = nullptr ); + template std::unique_ptr< T > fetchStacObject( const QUrl &url, QString *error = nullptr ); /** * Fetches a feature collection from \a url using a blocking network request. @@ -115,7 +116,7 @@ class CORE_EXPORT QgsStacController : public QObject * \see fetchStacObjectAsync * \see finishedStacObjectRequest */ - QgsStacObject *takeStacObject( int requestId ); + template std::unique_ptr< T > takeStacObject( int requestId ); /** * Returns the feature collection fetched with the specified \a requestId diff --git a/src/core/stac/qgsstacdataitems.cpp b/src/core/stac/qgsstacdataitems.cpp index f36c23b6adc..f3b661ecdd1 100644 --- a/src/core/stac/qgsstacdataitems.cpp +++ b/src/core/stac/qgsstacdataitems.cpp @@ -69,8 +69,7 @@ QVector QgsStacItemItem::createChildren() { QgsStacController *controller = stacController(); QString error; - std::unique_ptr< QgsStacObject > obj = controller->fetchStacObject( mPath, &error ); - setStacItem( obj ); + setStacItem( controller->fetchStacObject( mPath, &error ) ); if ( !mStacItem ) return { new QgsErrorItem( this, error, path() + QStringLiteral( "/error" ) ) }; @@ -177,16 +176,9 @@ QgsStacController *QgsStacItemItem::stacController() return nullptr; } -void QgsStacItemItem::setStacItem( std::unique_ptr< QgsStacObject > &object ) +void QgsStacItemItem::setStacItem( std::unique_ptr item ) { - QgsStacItem *item = dynamic_cast( object.get() ); - if ( item ) - { - // release object, mStacItem will take ownership of the successfully cast item - ( void )object.release(); - } - - mStacItem.reset( item ); + mStacItem = std::move( item ); updateToolTip(); } @@ -198,8 +190,8 @@ QgsStacItem *QgsStacItemItem::stacItem() const void QgsStacItemItem::itemRequestFinished( int requestId, QString error ) { QgsStacController *controller = stacController(); - std::unique_ptr< QgsStacObject > object = controller->takeStacObject( requestId ); - setStacItem( object ); + std::unique_ptr< QgsStacItem > object = controller->takeStacObject< QgsStacItem >( requestId ); + setStacItem( std::move( object ) ); if ( mStacItem ) { mIconName = QStringLiteral( "mActionPropertiesWidget.svg" ); @@ -327,8 +319,7 @@ QVector QgsStacCatalogItem::createChildren() QgsStacController *controller = stacController(); QString error; - std::unique_ptr< QgsStacObject > obj = controller->fetchStacObject( mPath, &error ); - setStacCatalog( obj ); + setStacCatalog( controller->fetchStacObject< QgsStacCatalog >( mPath, &error ) ); if ( !mStacCatalog ) return { new QgsErrorItem( this, error, path() + QStringLiteral( "/error" ) ) }; @@ -460,16 +451,9 @@ void QgsStacCatalogItem::updateToolTip() } } -void QgsStacCatalogItem::setStacCatalog( std::unique_ptr< QgsStacObject > &object ) +void QgsStacCatalogItem::setStacCatalog( std::unique_ptr catalog ) { - QgsStacCatalog *catalog = dynamic_cast( object.get() ); - if ( catalog ) - { - // release object, mStacCatalog will take ownership of the successfully cast catalog - ( void )object.release(); - } - - mStacCatalog.reset( catalog ); + mStacCatalog = std::move( catalog ); if ( mStacCatalog ) { if ( mName.isEmpty() && !mStacCatalog->title().isEmpty() ) @@ -498,12 +482,12 @@ QVector< QgsDataItem * > QgsStacCatalogItem::createItems( const QVector object( item ); + std::unique_ptr< QgsStacItem > object( item ); const QString name = item->properties().value( QStringLiteral( "title" ), item->id() ).toString(); QgsStacItemItem *i = new QgsStacItemItem( this, name, item->url() ); - i->setStacItem( object ); + i->setStacItem( std::move( object ) ); i->setState( Qgis::BrowserItemState::Populated ); contents.append( i ); } @@ -519,12 +503,12 @@ QVector QgsStacCatalogItem::createCollections( const QVector object( col ); + std::unique_ptr< QgsStacCollection > object( col ); const QString name = col->title().isEmpty() ? col->id() : col->title(); QgsStacCatalogItem *i = new QgsStacCatalogItem( this, name, col->url() ); - i->setStacCatalog( object ); + i->setStacCatalog( std::move( object ) ); contents.append( i ); } return contents; diff --git a/src/core/stac/qgsstacdataitems.h b/src/core/stac/qgsstacdataitems.h index 89f947c48d8..eb525e75b07 100644 --- a/src/core/stac/qgsstacdataitems.h +++ b/src/core/stac/qgsstacdataitems.h @@ -59,7 +59,7 @@ class CORE_EXPORT QgsStacItemItem : public QgsDataItem QgsStacController *stacController(); //! takes ownership - void setStacItem( std::unique_ptr< QgsStacObject > &object ); + void setStacItem( std::unique_ptr< QgsStacItem > item ); //! does not transfer ownership QgsStacItem *stacItem() const; @@ -87,7 +87,7 @@ class CORE_EXPORT QgsStacCatalogItem : public QgsDataCollectionItem void updateToolTip(); //! takes ownership - void setStacCatalog( std::unique_ptr< QgsStacObject > &object ); + void setStacCatalog( std::unique_ptr< QgsStacCatalog > object ); //! does not transfer ownership QgsStacCatalog *stacCatalog() const; diff --git a/src/core/stac/qgsstacparser.cpp b/src/core/stac/qgsstacparser.cpp index 089adb8c03e..e901bf3cff8 100644 --- a/src/core/stac/qgsstacparser.cpp +++ b/src/core/stac/qgsstacparser.cpp @@ -69,12 +69,12 @@ QString QgsStacParser::error() const return mError; } -QgsStacCatalog *QgsStacParser::catalog() +std::unique_ptr QgsStacParser::catalog() { return parseCatalog( mData ); } -QgsStacCatalog *QgsStacParser::parseCatalog( const nlohmann::json &data ) +std::unique_ptr QgsStacParser::parseCatalog( const nlohmann::json &data ) { try { @@ -118,7 +118,7 @@ QgsStacCatalog *QgsStacParser::parseCatalog( const nlohmann::json &data ) catalog->setStacExtensions( extensions ); } - return catalog.release(); + return catalog; } catch ( nlohmann::json::exception &ex ) { @@ -128,12 +128,12 @@ QgsStacCatalog *QgsStacParser::parseCatalog( const nlohmann::json &data ) } } -QgsStacCollection *QgsStacParser::collection() +std::unique_ptr QgsStacParser::collection() { return parseCollection( mData ); } -QgsStacCollection *QgsStacParser::parseCollection( const nlohmann::json &data ) +std::unique_ptr QgsStacParser::parseCollection( const nlohmann::json &data ) { try { @@ -281,7 +281,7 @@ QgsStacCollection *QgsStacParser::parseCollection( const nlohmann::json &data ) collection->setAssets( assets ); } - return collection.release(); + return collection; } catch ( nlohmann::json::exception &ex ) { @@ -291,12 +291,12 @@ QgsStacCollection *QgsStacParser::parseCollection( const nlohmann::json &data ) } } -QgsStacItem *QgsStacParser::item() +std::unique_ptr QgsStacParser::item() { return parseItem( mData ); } -QgsStacItem *QgsStacParser::parseItem( const nlohmann::json &data ) +std::unique_ptr QgsStacParser::parseItem( const nlohmann::json &data ) { try { @@ -379,7 +379,7 @@ QgsStacItem *QgsStacParser::parseItem( const nlohmann::json &data ) if ( data.contains( "collection" ) ) item->setCollection( getString( data["collection"] ) ); - return item.release(); + return item; } catch ( nlohmann::json::exception &ex ) { @@ -464,7 +464,7 @@ QString QgsStacParser::getString( const nlohmann::json &data ) return data.is_null() ? QString() : QString::fromStdString( data ); } -QgsStacItemCollection *QgsStacParser::itemCollection() +std::unique_ptr QgsStacParser::itemCollection() { std::vector< std::unique_ptr > items; QVector< QgsStacLink > links; @@ -497,7 +497,7 @@ QgsStacItemCollection *QgsStacParser::itemCollection() rawItems.append( i.release() ); } - return new QgsStacItemCollection( rawItems, links, numberMatched ); + return std::make_unique< QgsStacItemCollection >( rawItems, links, numberMatched ); } QgsStacCollections *QgsStacParser::collections() diff --git a/src/core/stac/qgsstacparser.h b/src/core/stac/qgsstacparser.h index 137b0f28ae7..93545ba50e6 100644 --- a/src/core/stac/qgsstacparser.h +++ b/src/core/stac/qgsstacparser.h @@ -59,28 +59,28 @@ class QgsStacParser * If parsing failed, NULLPTR is returned * The caller takes ownership of the returned catalog */ - QgsStacCatalog *catalog(); + std::unique_ptr< QgsStacCatalog > catalog(); /** * Returns the parsed STAC Collection * If parsing failed, NULLPTR is returned * The caller takes ownership of the returned collection */ - QgsStacCollection *collection(); + std::unique_ptr< QgsStacCollection > collection(); /** * Returns the parsed STAC Item * If parsing failed, NULLPTR is returned * The caller takes ownership of the returned item */ - QgsStacItem *item(); + std::unique_ptr< QgsStacItem > item(); /** * Returns the parsed STAC API Item Collection * If parsing failed, NULLPTR is returned * The caller takes ownership of the returned item collection */ - QgsStacItemCollection *itemCollection(); + std::unique_ptr< QgsStacItemCollection > itemCollection(); /** * Returns the parsed STAC API Collections @@ -96,9 +96,9 @@ class QgsStacParser QString error() const; private: - QgsStacItem *parseItem( const nlohmann::json &data ); - QgsStacCatalog *parseCatalog( const nlohmann::json &data ); - QgsStacCollection *parseCollection( const nlohmann::json &data ); + std::unique_ptr< QgsStacItem > parseItem( const nlohmann::json &data ); + std::unique_ptr< QgsStacCatalog > parseCatalog( const nlohmann::json &data ); + std::unique_ptr< QgsStacCollection > parseCollection( const nlohmann::json &data ); QVector< QgsStacLink > parseLinks( const nlohmann::json &data ); QMap< QString, QgsStacAsset > parseAssets( const nlohmann::json &data ); diff --git a/tests/src/core/testqgsstac.cpp b/tests/src/core/testqgsstac.cpp index 342892a0d1e..02b9534f548 100644 --- a/tests/src/core/testqgsstac.cpp +++ b/tests/src/core/testqgsstac.cpp @@ -75,10 +75,9 @@ void TestQgsStac::testParseLocalCatalog() { const QUrl url( QStringLiteral( "file://%1%2" ).arg( mDataDir, QStringLiteral( "catalog.json" ) ) ); QgsStacController c; - std::unique_ptr< QgsStacObject > obj = c.fetchStacObject( url.toString() ); - QVERIFY( obj ); - QCOMPARE( obj->type(), QgsStacObject::Type::Catalog ); - QgsStacCatalog *cat = dynamic_cast( obj.get() ); + std::unique_ptr< QgsStacCatalog > cat = c.fetchStacObject< QgsStacCatalog >( url.toString() ); + QVERIFY( cat ); + QCOMPARE( cat->type(), QgsStacObject::Type::Catalog ); QVERIFY( cat ); QCOMPARE( cat->id(), QLatin1String( "examples" ) ); @@ -103,10 +102,9 @@ void TestQgsStac::testParseLocalCollection() { const QUrl url( QStringLiteral( "file://%1%2" ).arg( mDataDir, QStringLiteral( "collection.json" ) ) ); QgsStacController c; - std::unique_ptr< QgsStacObject > obj = c.fetchStacObject( url.toString() ); - QVERIFY( obj ); - QCOMPARE( obj->type(), QgsStacObject::Type::Collection ); - QgsStacCollection *col = dynamic_cast( obj.get() ); + std::unique_ptr< QgsStacCollection > col = c.fetchStacObject< QgsStacCollection >( url.toString() ); + QVERIFY( col ); + QCOMPARE( col->type(), QgsStacObject::Type::Collection ); QVERIFY( col ); QCOMPARE( col->id(), QLatin1String( "simple-collection" ) ); @@ -151,10 +149,9 @@ void TestQgsStac::testParseLocalItem() { const QUrl url( QStringLiteral( "file://%1%2" ).arg( mDataDir, QStringLiteral( "core-item.json" ) ) ); QgsStacController c; - std::unique_ptr< QgsStacObject > obj = c.fetchStacObject( url.toString() ); - QVERIFY( obj ); - QCOMPARE( obj->type(), QgsStacObject::Type::Item ); - QgsStacItem *item = dynamic_cast( obj.get() ); + std::unique_ptr< QgsStacItem > item = c.fetchStacObject< QgsStacItem >( url.toString() ); + QVERIFY( item ); + QCOMPARE( item->type(), QgsStacObject::Type::Item ); QVERIFY( item ); QCOMPARE( item->id(), QLatin1String( "20201211_223832_CS2" ) );