mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-03 00:04:47 -04:00
feat(#62838): support single asset downloads
This commit is contained in:
parent
8906518d27
commit
48f2d22a0a
@ -87,17 +87,17 @@ Returns a uri for the asset if it is a cloud optimized file like COG or
|
||||
COPC
|
||||
|
||||
.. versionadded:: 3.42
|
||||
%End
|
||||
|
||||
QString toHtml() const;
|
||||
%Docstring
|
||||
Returns an HTML representation of the STAC Asset without an ID
|
||||
%End
|
||||
|
||||
QString toHtml( const QString &assetId ) const;
|
||||
%Docstring
|
||||
Returns an HTML representation of the STAC Asset including its ID within
|
||||
its container
|
||||
%End
|
||||
|
||||
bool isDownloadable() const;
|
||||
%Docstring
|
||||
Returns whether the asset can be downloaded
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -82,14 +82,12 @@ Sets the item's additional metadata to ``properties``
|
||||
|
||||
QMap< QString, QgsStacAsset > assets() const;
|
||||
%Docstring
|
||||
Returns a dictionary of asset objects that can be downloaded, each with
|
||||
a unique key.
|
||||
Returns a dictionary of asset objects, each with a unique key.
|
||||
%End
|
||||
|
||||
void setAssets( const QMap< QString, QgsStacAsset > &assets );
|
||||
%Docstring
|
||||
Sets the ``asset`` objects that can be downloaded, each with a unique
|
||||
key.
|
||||
Sets the ``asset`` objects, each with a unique key.
|
||||
%End
|
||||
|
||||
QString collection() const;
|
||||
|
@ -87,17 +87,17 @@ Returns a uri for the asset if it is a cloud optimized file like COG or
|
||||
COPC
|
||||
|
||||
.. versionadded:: 3.42
|
||||
%End
|
||||
|
||||
QString toHtml() const;
|
||||
%Docstring
|
||||
Returns an HTML representation of the STAC Asset without an ID
|
||||
%End
|
||||
|
||||
QString toHtml( const QString &assetId ) const;
|
||||
%Docstring
|
||||
Returns an HTML representation of the STAC Asset including its ID within
|
||||
its container
|
||||
%End
|
||||
|
||||
bool isDownloadable() const;
|
||||
%Docstring
|
||||
Returns whether the asset can be downloaded
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -82,14 +82,12 @@ Sets the item's additional metadata to ``properties``
|
||||
|
||||
QMap< QString, QgsStacAsset > assets() const;
|
||||
%Docstring
|
||||
Returns a dictionary of asset objects that can be downloaded, each with
|
||||
a unique key.
|
||||
Returns a dictionary of asset objects, each with a unique key.
|
||||
%End
|
||||
|
||||
void setAssets( const QMap< QString, QgsStacAsset > &assets );
|
||||
%Docstring
|
||||
Sets the ``asset`` objects that can be downloaded, each with a unique
|
||||
key.
|
||||
Sets the ``asset`` objects, each with a unique key.
|
||||
%End
|
||||
|
||||
QString collection() const;
|
||||
|
@ -154,12 +154,6 @@ QgsMimeDataUtils::Uri QgsStacAsset::uri( QString authcfg ) const
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
QString QgsStacAsset::toHtml() const
|
||||
{
|
||||
return toHtml( QString() );
|
||||
}
|
||||
|
||||
QString QgsStacAsset::toHtml( const QString &assetId ) const
|
||||
{
|
||||
QString html = QStringLiteral( "<h1>%1</h1>\n<hr>\n" ).arg( QLatin1String( "Asset" ) );
|
||||
@ -173,3 +167,20 @@ QString QgsStacAsset::toHtml( const QString &assetId ) const
|
||||
html += QStringLiteral( "</table><br/>\n" );
|
||||
return html;
|
||||
}
|
||||
|
||||
bool QgsStacAsset::isDownloadable() const
|
||||
{
|
||||
/*
|
||||
* Directory-based data types like Zarr should not offer downloads.
|
||||
* Download attempts might
|
||||
* - fail with 4xx,
|
||||
* - succeed but download an HTML directory listing response, or
|
||||
* - something else that does not meet the user's needs.
|
||||
*/
|
||||
if ( formatName() == QLatin1String( "Zarr" ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -84,16 +84,16 @@ class CORE_EXPORT QgsStacAsset
|
||||
*/
|
||||
QgsMimeDataUtils::Uri uri( QString authcfg ) const;
|
||||
|
||||
/**
|
||||
* Returns an HTML representation of the STAC Asset without an ID
|
||||
*/
|
||||
QString toHtml() const;
|
||||
|
||||
/**
|
||||
* Returns an HTML representation of the STAC Asset including its ID within its container
|
||||
*/
|
||||
QString toHtml( const QString &assetId ) const;
|
||||
|
||||
/**
|
||||
* Returns whether the asset can be downloaded
|
||||
*/
|
||||
bool isDownloadable() const;
|
||||
|
||||
private:
|
||||
QString mHref;
|
||||
QString mTitle;
|
||||
|
@ -76,10 +76,10 @@ class CORE_EXPORT QgsStacItem : public QgsStacObject
|
||||
//! Sets the item's additional metadata to \a properties
|
||||
void setProperties( const QVariantMap &properties );
|
||||
|
||||
//! Returns a dictionary of asset objects that can be downloaded, each with a unique key.
|
||||
//! Returns a dictionary of asset objects, each with a unique key.
|
||||
QMap< QString, QgsStacAsset > assets() const;
|
||||
|
||||
//! Sets the \a asset objects that can be downloaded, each with a unique key.
|
||||
//! Sets the \a asset objects, each with a unique key.
|
||||
void setAssets( const QMap< QString, QgsStacAsset > &assets );
|
||||
|
||||
//! Returns the id of the STAC Collection this Item references to
|
||||
|
@ -89,9 +89,21 @@ void QgsStacDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *
|
||||
{
|
||||
menu->addSeparator();
|
||||
|
||||
QAction *actionDownload = new QAction( tr( "Download Assets…" ), menu );
|
||||
connect( actionDownload, &QAction::triggered, this, [itemItem, context] { downloadAssets( itemItem, context ); } );
|
||||
menu->addAction( actionDownload );
|
||||
int downloadableAssets = 0;
|
||||
const QMap<QString, QgsStacAsset> assets = itemItem->stacItem()->assets();
|
||||
for ( auto it = assets.constBegin(); it != assets.constEnd(); ++it )
|
||||
{
|
||||
if ( it.value().isDownloadable() )
|
||||
{
|
||||
downloadableAssets += 1;
|
||||
}
|
||||
}
|
||||
if ( downloadableAssets > 0 )
|
||||
{
|
||||
QAction *actionDownload = new QAction( tr( "Download Assets…" ), menu );
|
||||
connect( actionDownload, &QAction::triggered, this, [itemItem, context] { downloadAssets( itemItem, context ); } );
|
||||
menu->addAction( actionDownload );
|
||||
}
|
||||
|
||||
QAction *actionDetails = new QAction( tr( "Details…" ), menu );
|
||||
connect( actionDetails, &QAction::triggered, this, [itemItem] { showDetails( itemItem ); } );
|
||||
@ -101,9 +113,12 @@ void QgsStacDataItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *
|
||||
|
||||
if ( QgsStacAssetItem *assetItem = qobject_cast<QgsStacAssetItem *>( item ) )
|
||||
{
|
||||
QAction *actionDownload = new QAction( tr( "Download Asset…" ), menu );
|
||||
connect( actionDownload, &QAction::triggered, this, [assetItem, context] { downloadAssets( assetItem, context ); } );
|
||||
menu->addAction( actionDownload );
|
||||
if ( assetItem->stacAsset()->isDownloadable() )
|
||||
{
|
||||
QAction *actionDownload = new QAction( tr( "Download Asset…" ), menu );
|
||||
connect( actionDownload, &QAction::triggered, this, [assetItem, context] { downloadAssets( assetItem, context ); } );
|
||||
menu->addAction( actionDownload );
|
||||
}
|
||||
|
||||
QAction *actionDetails = new QAction( tr( "Details…" ), menu );
|
||||
connect( actionDetails, &QAction::triggered, this, [assetItem] { showDetails( assetItem ); } );
|
||||
@ -199,7 +214,7 @@ void QgsStacDataItemGuiProvider::showDetails( QgsDataItem *item )
|
||||
QgsStacObjectDetailsDialog d;
|
||||
QgsStacItemItem *itemItem = qobject_cast<QgsStacItemItem *>( assetItem->parent() );
|
||||
d.setAuthcfg( itemItem->stacController()->authCfg() );
|
||||
d.setContentFromStacAsset( assetItem->stacAsset() );
|
||||
d.setContentFromStacAsset( assetItem->name(), assetItem->stacAsset() );
|
||||
d.exec();
|
||||
return;
|
||||
}
|
||||
@ -208,12 +223,21 @@ void QgsStacDataItemGuiProvider::showDetails( QgsDataItem *item )
|
||||
void QgsStacDataItemGuiProvider::downloadAssets( QgsDataItem *item, QgsDataItemGuiContext context )
|
||||
{
|
||||
QgsStacItemItem *itemItem = qobject_cast<QgsStacItemItem *>( item );
|
||||
QgsStacAssetItem *assetItem = qobject_cast<QgsStacAssetItem *>( item );
|
||||
|
||||
if ( !itemItem )
|
||||
if ( !( itemItem || assetItem ) )
|
||||
return;
|
||||
|
||||
QgsStacDownloadAssetsDialog dialog;
|
||||
dialog.setStacItem( itemItem->stacItem() );
|
||||
if ( itemItem )
|
||||
{
|
||||
dialog.setStacItem( itemItem->stacItem() );
|
||||
}
|
||||
else if ( assetItem )
|
||||
{
|
||||
itemItem = qobject_cast<QgsStacItemItem *>( assetItem->parent() );
|
||||
dialog.addStacAsset( assetItem->name(), assetItem->stacAsset() );
|
||||
}
|
||||
dialog.setMessageBar( context.messageBar() );
|
||||
dialog.setAuthCfg( itemItem->stacController()->authCfg() );
|
||||
dialog.exec();
|
||||
|
@ -150,25 +150,34 @@ void QgsStacDownloadAssetsDialog::setStacItem( QgsStacItem *stacItem )
|
||||
const QMap<QString, QgsStacAsset> assets = stacItem->assets();
|
||||
for ( auto it = assets.constBegin(); it != assets.constEnd(); ++it )
|
||||
{
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem();
|
||||
item->setText( 0, it.key() );
|
||||
item->setToolTip( 0, it.key() );
|
||||
item->setCheckState( 0, Qt::Checked );
|
||||
item->setText( 1, it->title() );
|
||||
item->setToolTip( 1, it->title() );
|
||||
item->setText( 2, it->description() );
|
||||
item->setToolTip( 2, it->description() );
|
||||
item->setText( 3, it->roles().join( "," ) );
|
||||
item->setToolTip( 3, it->roles().join( "," ) );
|
||||
item->setText( 4, it->mediaType() );
|
||||
item->setToolTip( 4, it->mediaType() );
|
||||
item->setText( 5, it->href() );
|
||||
item->setToolTip( 5, it->href() );
|
||||
|
||||
mTreeWidget->addTopLevelItem( item );
|
||||
if ( it.value().isDownloadable() )
|
||||
{
|
||||
addStacAsset( it.key(), &it.value() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsStacDownloadAssetsDialog::addStacAsset( const QString &assetId, const QgsStacAsset *stacAsset )
|
||||
{
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem();
|
||||
|
||||
item->setText( 0, assetId );
|
||||
item->setToolTip( 0, assetId );
|
||||
item->setCheckState( 0, Qt::Checked );
|
||||
item->setText( 1, stacAsset->title() );
|
||||
item->setToolTip( 1, stacAsset->title() );
|
||||
item->setText( 2, stacAsset->description() );
|
||||
item->setToolTip( 2, stacAsset->description() );
|
||||
item->setText( 3, stacAsset->roles().join( "," ) );
|
||||
item->setToolTip( 3, stacAsset->roles().join( "," ) );
|
||||
item->setText( 4, stacAsset->mediaType() );
|
||||
item->setToolTip( 4, stacAsset->mediaType() );
|
||||
item->setText( 5, stacAsset->href() );
|
||||
item->setToolTip( 5, stacAsset->href() );
|
||||
|
||||
mTreeWidget->addTopLevelItem( item );
|
||||
}
|
||||
|
||||
QString QgsStacDownloadAssetsDialog::selectedFolder()
|
||||
{
|
||||
return mFileWidget->filePath();
|
||||
|
@ -38,6 +38,7 @@ class QgsStacDownloadAssetsDialog : public QDialog, private Ui::QgsStacDownloadA
|
||||
void setAuthCfg( const QString &authCfg );
|
||||
void setMessageBar( QgsMessageBar *bar );
|
||||
void setStacItem( QgsStacItem *stacItem );
|
||||
void addStacAsset( const QString &assetId, const QgsStacAsset *stacAsset );
|
||||
QString selectedFolder();
|
||||
QStringList selectedUrls();
|
||||
|
||||
|
@ -56,14 +56,14 @@ void QgsStacObjectDetailsDialog::setContentFromStacObject( QgsStacObject *stacOb
|
||||
}
|
||||
|
||||
|
||||
void QgsStacObjectDetailsDialog::setContentFromStacAsset( const QgsStacAsset *stacAsset )
|
||||
void QgsStacObjectDetailsDialog::setContentFromStacAsset( const QString &assetId, const QgsStacAsset *stacAsset )
|
||||
{
|
||||
QString thumbnailHtml = QString( "" );
|
||||
if ( isThumbnailAsset( stacAsset ) )
|
||||
{
|
||||
thumbnailHtml = thumbnailHtmlContent( stacAsset );
|
||||
}
|
||||
QString bodyHtml = stacAsset->toHtml();
|
||||
QString bodyHtml = stacAsset->toHtml( assetId );
|
||||
setContent( bodyHtml, thumbnailHtml );
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ class QgsStacObjectDetailsDialog : public QDialog, private Ui::QgsStacObjectDeta
|
||||
void setAuthcfg( const QString &authcfg );
|
||||
|
||||
void setContentFromStacObject( QgsStacObject *stacObject );
|
||||
void setContentFromStacAsset( const QgsStacAsset *stacAsset );
|
||||
void setContentFromStacAsset( const QString &assetId, const QgsStacAsset *stacAsset );
|
||||
|
||||
private:
|
||||
QString mAuthcfg;
|
||||
|
@ -194,6 +194,7 @@ void TestQgsStac::testParseLocalItem()
|
||||
QCOMPARE( asset.href(), basePath + QStringLiteral( "20201211_223832_CS2_analytic.tif" ) );
|
||||
QVERIFY( asset.isCloudOptimized() );
|
||||
QCOMPARE( asset.formatName(), QStringLiteral( "COG" ) );
|
||||
QVERIFY( asset.isDownloadable() );
|
||||
|
||||
QgsMimeDataUtils::Uri uri = asset.uri();
|
||||
QCOMPARE( uri.uri, basePath + QStringLiteral( "20201211_223832_CS2_analytic.tif" ) );
|
||||
@ -207,6 +208,7 @@ void TestQgsStac::testParseLocalItem()
|
||||
QVERIFY( !uri.isValid() );
|
||||
QVERIFY( uri.uri.isEmpty() );
|
||||
QVERIFY( uri.name.isEmpty() );
|
||||
QVERIFY( asset.isDownloadable() );
|
||||
|
||||
// normal geotiff is not cloud optimized
|
||||
asset = item->assets().value( QStringLiteral( "udm" ), QgsStacAsset( {}, {}, {}, {}, {} ) );
|
||||
@ -216,12 +218,14 @@ void TestQgsStac::testParseLocalItem()
|
||||
QVERIFY( !uri.isValid() );
|
||||
QVERIFY( uri.uri.isEmpty() );
|
||||
QVERIFY( uri.name.isEmpty() );
|
||||
QVERIFY( asset.isDownloadable() );
|
||||
|
||||
// Zarr recognised as cloud optimized
|
||||
asset = item->assets().value( QStringLiteral( "zarr-store" ), QgsStacAsset( {}, {}, {}, {}, {} ) );
|
||||
QVERIFY( asset.isCloudOptimized() );
|
||||
QCOMPARE( asset.formatName(), QStringLiteral( "Zarr" ) );
|
||||
QCOMPARE( asset.uri().layerType, QStringLiteral( "raster" ) );
|
||||
QVERIFY( !asset.isDownloadable() );
|
||||
}
|
||||
|
||||
void TestQgsStac::testParseLocalItemCollection()
|
||||
|
Loading…
x
Reference in New Issue
Block a user