Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
uclaros committed Aug 16, 2024
1 parent 7ccb20c commit 04503bc
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 33 deletions.
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ set(QGIS_CORE_SRCS
stac/qgsstaccontroller.cpp
stac/qgsstacdataitems.cpp
stac/qgsstacextent.cpp
stac/qgsstacfeaturecollection.cpp
stac/qgsstacitem.cpp
stac/qgsstacobject.cpp
stac/qgsstacparser.cpp
Expand Down Expand Up @@ -1933,6 +1934,7 @@ set(QGIS_CORE_HDRS
stac/qgsstaccontroller.h
stac/qgsstacdataitems.h
stac/qgsstacextent.h
stac/qgsstacfeaturecollection.h
stac/qgsstacitem.h
stac/qgsstacobject.h
stac/qgsstacparser.h
Expand Down
32 changes: 30 additions & 2 deletions src/core/stac/qgsstaccontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ QgsStacController::QgsStacController()
{
}

QgsStacObject *QgsStacController::fetch( QUrl url )
QgsStacObject *QgsStacController::fetchObject( QUrl url )
{
QNetworkRequest req( url );
QgsNetworkAccessManager *nam = QgsNetworkAccessManager::instance();
Expand All @@ -34,7 +34,7 @@ QgsStacObject *QgsStacController::fetch( QUrl url )
if ( content.error() != QNetworkReply::NoError )
return nullptr;

auto data = content.content();
const QByteArray data = content.content();

QgsStacParser parser;
parser.setData( data );
Expand All @@ -47,11 +47,39 @@ QgsStacObject *QgsStacController::fetch( QUrl url )
case QgsStacObject::Type::Item:
return new QgsStacItem( parser.item() );
case QgsStacObject::Type::Unknown:
case QgsStacObject::Type::FeatureCollection:
return nullptr;
}
Q_UNREACHABLE();
}

QgsStacFeatureCollection *QgsStacController::fetchItems( QUrl url )
{
QNetworkRequest req( url );
QgsNetworkAccessManager *nam = QgsNetworkAccessManager::instance();

QgsNetworkReplyContent content = nam->blockingGet( req );

if ( content.error() != QNetworkReply::NoError )
return nullptr;

const QByteArray data = content.content();

QgsStacParser parser;
parser.setData( data );
switch ( parser.type() )
{
case QgsStacObject::Type::Catalog:
case QgsStacObject::Type::Collection:
case QgsStacObject::Type::Item:
case QgsStacObject::Type::Unknown:
return nullptr;
case QgsStacObject::Type::FeatureCollection:
return new QgsStacFeatureCollection( parser.featureCollection() );
}
Q_UNREACHABLE();
}

QgsStacCatalog QgsStacController::openLocalCatalog( const QString &fileName ) const
{
QFile file( fileName );
Expand Down
3 changes: 2 additions & 1 deletion src/core/stac/qgsstaccontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class CORE_EXPORT QgsStacController : public QObject
QgsStacItem openLocalItem( const QString &fileName ) const;


QgsStacObject *fetch( QUrl url );
QgsStacObject *fetchObject( QUrl url );
QgsStacFeatureCollection *fetchItems( QUrl url );

signals:

Expand Down
119 changes: 113 additions & 6 deletions src/core/stac/qgsstacdataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,67 @@
#include "stac/qgsstaccontroller.h"





//
// QgsStacAssetItem
// QgsStacFetchMoreItem
//

QgsStacAssetItem::QgsStacAssetItem( QgsDataItem *parent, QString name, QString path, QString uri )
QgsStacFetchMoreItem::QgsStacFetchMoreItem( QgsDataItem *parent, QString name, QString path, QString uri )
: QgsDataItem( Qgis::BrowserItemType::Custom, parent, name, path, uri )
{
mIconName = QStringLiteral( "mIconFieldArrayString.svg" );
mToolTip = QStringLiteral( "%1\n%2" ).arg( name, uri );
}

bool QgsStacFetchMoreItem::handleDoubleClick()
{
QgsStacCatalogItem *c = dynamic_cast<QgsStacCatalogItem *>( mParent );
if ( !c )
return false;


c->fetchMoreChildren();

return true;
}

//
// QgsStacAssetItem
//

QgsStacAssetItem::QgsStacAssetItem( QgsDataItem *parent, QgsStacAsset asset )
: QgsDataItem( Qgis::BrowserItemType::Custom, parent, asset.title, asset.title )
, mAsset( asset )
{
mIconName = QStringLiteral( "mIconFieldArrayString.svg" );
mToolTip = QStringLiteral( "%1<br>%2<br>%3<br>%4" ).arg( asset.title, asset.href, asset.mediaType, asset.description );
mState = Qgis::BrowserItemState::Populated;
}

bool QgsStacAssetItem::hasDragEnabled() const
{
return mAsset.mediaType == QLatin1String( "image/tiff; application=geotiff; profile=cloud-optimized" );
}

QgsMimeDataUtils::UriList QgsStacAssetItem::mimeUris() const
{
QgsMimeDataUtils::Uri uri;
uri.layerType = QStringLiteral( "raster" );
uri.providerKey = QStringLiteral( "gdal" );
uri.uri = mAsset.href;
uri.name = mAsset.title;
return { uri, uri };
}


//
// QgsStacItemItem
//

QgsStacItemItem::QgsStacItemItem( QgsDataItem *parent, QString name, QString path, QString uri )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "stac" ) )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "special:Stac" ) )
{
mIconName = QStringLiteral( "mActionPropertiesWidget.svg" );
mToolTip = QStringLiteral( "%1\n%2" ).arg( name, uri );
Expand All @@ -53,7 +96,7 @@ QVector<QgsDataItem *> QgsStacItemItem::createChildren()
//

QgsStacCatalogItem::QgsStacCatalogItem( QgsDataItem *parent, QString name, QString path, QString uri )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "stac" ) )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "special:Stac" ) )
, mUri( uri )
{
mIconName = QStringLiteral( "mIconFolder.svg" );
Expand All @@ -65,7 +108,7 @@ QVector<QgsDataItem *> QgsStacCatalogItem::createChildren()
{
auto d = QgsStacConnection::decodedUri( mUri );
QgsStacController c;
auto i = c.fetch( d.url );
auto i = c.fetchObject( d.url );
if ( !i || i->type() != QgsStacObject::Type::Catalog )
return { new QgsErrorItem( this, i ? QStringLiteral( "This is not a catalog!" ) : QStringLiteral( "Error fetching..." ), QStringLiteral( "stac" ) ) };

Expand Down Expand Up @@ -100,6 +143,38 @@ QVector<QgsDataItem *> QgsStacCatalogItem::createChildren()
else if ( link.relation == QLatin1String( "items" ) )
{
// stac api items (ogcapi features)
const QgsStacFeatureCollection *fc = c.fetchItems( d.url ); // todo: pass Data or encodedUri?
if ( fc )
{
for ( const auto &item : fc->items() )
{
if ( !item.isValid() )
continue;

d.url = item.url();
const QString name = item.properties().value( QStringLiteral( "title" ), item.id() ).toString();
QgsStacItemItem *i = new QgsStacItemItem( this, name, d.url, QgsStacConnection::encodedUri( d ) );
QString toolTip = QStringLiteral( "%1\n%2\n%3" ).arg( name, item.id(), d.url );

for ( const auto &asset : item.assets() )
{
if ( asset.roles.contains( QLatin1String( "data" ) ) )
{
QgsStacAssetItem *a = new QgsStacAssetItem( i, asset );
i->addChild( a );
}
if ( asset.roles.contains( QLatin1String( "thumbnail" ) ) )
{
toolTip.prepend( QStringLiteral( "<img src='%2'><br>" ).arg( asset.href ) );
}
}

i->setToolTip( toolTip );
i->setState( Qgis::BrowserItemState::Populated );
contents.append( i );
}
}
mFetchMoreUrl = fc->nextUrl();
}
else if ( link.mediaType == QLatin1String( "application/json" ) )
{
Expand All @@ -110,9 +185,41 @@ QVector<QgsDataItem *> QgsStacCatalogItem::createChildren()
// should handle other links?
}
}

if ( !mFetchMoreUrl.isEmpty() )
{
mFetchMoreItem = new QgsStacFetchMoreItem( this, QStringLiteral( "Fetch more items..." ), QString(), QString() );
contents.append( mFetchMoreItem );
}
return contents;
}

void QgsStacCatalogItem::fetchMoreChildren()
{
QgsStacController c;
const QgsStacFeatureCollection *fc = c.fetchItems( mFetchMoreUrl );
if ( fc )
{
auto d = QgsStacConnection::decodedUri( mUri );
for ( const auto &item : fc->items() )
{
if ( !item.isValid() )
continue;

d.url = item.url();
QgsStacItemItem *i = new QgsStacItemItem( this, item.id(), d.url, QgsStacConnection::encodedUri( d ) );
i->setToolTip( QStringLiteral( "%1\n%2" ).arg( item.id(), d.url ) );
addChildItem( i, true );
}
}
mFetchMoreUrl = fc->nextUrl();
if ( mFetchMoreUrl.isEmpty() && mFetchMoreItem )
{
removeChildItem( mFetchMoreItem );
mFetchMoreItem = nullptr;
}
}


//
// QgsStacCollectionItem
Expand All @@ -130,7 +237,7 @@ QgsStacCollectionItem::QgsStacCollectionItem( QgsDataItem *parent, QString name,
//

QgsStacRootItem::QgsStacRootItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "stac" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "special:Stac" ) ) // todo: do we actually need Provider?
{
mCapabilities |= Qgis::BrowserItemCapability::Fast;
mIconName = QStringLiteral( "mIconStac.svg" );
Expand Down
25 changes: 24 additions & 1 deletion src/core/stac/qgsstacdataitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,33 @@
#include "qgis_core.h"
#include "qgsdataitemprovider.h"
#include "qgsconnectionsitem.h"
#include "qgsstacobject.h"


//
// QgsStacFetchMoreItem
//

class QgsStacFetchMoreItem : public QgsDataItem
{
Q_OBJECT
public:
QgsStacFetchMoreItem( QgsDataItem *parent, QString name, QString path, QString uri );
virtual bool handleDoubleClick() override;
};


class QgsStacAssetItem : public QgsDataItem
{
Q_OBJECT
public:
QgsStacAssetItem( QgsDataItem *parent, QString name, QString path, QString uri );
QgsStacAssetItem( QgsDataItem *parent, QgsStacAsset asset );

virtual bool hasDragEnabled() const override;
virtual QgsMimeDataUtils::UriList mimeUris() const override;

private:
QgsStacAsset mAsset;
};


Expand All @@ -47,10 +67,13 @@ class QgsStacCatalogItem : public QgsDataCollectionItem

QVector<QgsDataItem *> createChildren() override;
// bool equal( const QgsDataItem *other ) override;
void fetchMoreChildren();

protected:
//! The URI
QString mUri;
QString mFetchMoreUrl;
QgsDataItem *mFetchMoreItem = nullptr;
};


Expand Down
71 changes: 71 additions & 0 deletions src/core/stac/qgsstacfeaturecollection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/***************************************************************************
qgsstacfeaturecollection.cpp
---------------------
begin : August 2024
copyright : (C) 2024 by Stefanos Natsis
email : uclaros 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 "qgsstacfeaturecollection.h"

QgsStacFeatureCollection::QgsStacFeatureCollection( const QVector< QgsStacItem > items, const QVector< QgsStacLink > links )
: mValid( true )
, mItems( items )
, mLinks( links )
{
for ( const QgsStacLink &link : mLinks )
{
if ( link.relation == QLatin1String( "self" ) )
mUrl = link.href;
else if ( link.relation == QLatin1String( "root" ) )
mRootUrl = link.href;
else if ( link.relation == QLatin1String( "parent" ) )
mParentUrl = link.href;
else if ( link.relation == QLatin1String( "collection" ) )
mCollectionUrl = link.href;
else if ( link.relation == QLatin1String( "next" ) )
mNextUrl = link.href;
}
}

QVector< QgsStacItem > QgsStacFeatureCollection::items() const
{
return mItems;
}

QString QgsStacFeatureCollection::url() const
{
return mUrl;
}

QString QgsStacFeatureCollection::rootUrl() const
{
return mRootUrl;
}

QString QgsStacFeatureCollection::parentUrl() const
{
return mParentUrl;
}

QString QgsStacFeatureCollection::collectionUrl() const
{
return mCollectionUrl;
}

QString QgsStacFeatureCollection::nextUrl() const
{
return mNextUrl;
}

bool QgsStacFeatureCollection::isValid() const
{
return mValid;
}
Loading

0 comments on commit 04503bc

Please sign in to comment.