From fa4192dbe9bda7c4aa721500ca9f8ca0523abaa6 Mon Sep 17 00:00:00 2001 From: uclaros Date: Fri, 8 Aug 2025 09:59:48 +0300 Subject: [PATCH] Propagate STAC connection authcfg to assets The authcfg is now added to the layer uri and used for asset downloading and preview --- src/core/stac/qgsstacdataitems.cpp | 14 ++++++++--- src/core/stac/qgsstacdataitems.h | 2 +- src/gui/stac/qgsstacdataitemguiprovider.cpp | 3 +++ src/gui/stac/qgsstacitemlistmodel.cpp | 10 +++++--- src/gui/stac/qgsstacitemlistmodel.h | 2 +- src/gui/stac/qgsstacobjectdetailsdialog.cpp | 18 +++++++++++++- src/gui/stac/qgsstacobjectdetailsdialog.h | 5 ++++ src/gui/stac/qgsstacsourceselect.cpp | 26 +++++++++++++-------- src/gui/stac/qgsstacsourceselect.h | 2 +- 9 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/core/stac/qgsstacdataitems.cpp b/src/core/stac/qgsstacdataitems.cpp index eccdec2be19..075455e65bb 100644 --- a/src/core/stac/qgsstacdataitems.cpp +++ b/src/core/stac/qgsstacdataitems.cpp @@ -98,6 +98,8 @@ QgsMimeDataUtils::UriList QgsStacItemItem::mimeUris() const if ( !mStacItem ) return uris; + const QString authcfg = stacController()->authCfg(); + const QMap assets = mStacItem->assets(); for ( auto it = assets.constBegin(); it != assets.constEnd(); ++it ) { @@ -116,6 +118,8 @@ QgsMimeDataUtils::UriList QgsStacItemItem::mimeUris() const it->href().startsWith( QLatin1String( "ftp" ), Qt::CaseInsensitive ) ) { uri.uri = QStringLiteral( "/vsicurl/%1" ).arg( it->href() ); + if ( !authcfg.isEmpty() ) + uri.uri.append( QStringLiteral( " authcfg='%1'" ).arg( authcfg ) ); } else if ( it->href().startsWith( QLatin1String( "s3://" ), Qt::CaseInsensitive ) ) { @@ -131,12 +135,16 @@ QgsMimeDataUtils::UriList QgsStacItemItem::mimeUris() const uri.layerType = QStringLiteral( "pointcloud" ); uri.providerKey = QStringLiteral( "copc" ); uri.uri = it->href(); + if ( !authcfg.isEmpty() ) + uri.uri.append( QStringLiteral( " authcfg='%1'" ).arg( authcfg ) ); } else if ( it->href().endsWith( QLatin1String( "/ept.json" ) ) ) { uri.layerType = QStringLiteral( "pointcloud" ); uri.providerKey = QStringLiteral( "ept" ); uri.uri = it->href(); + if ( !authcfg.isEmpty() ) + uri.uri.append( QStringLiteral( " authcfg='%1'" ).arg( authcfg ) ); } uri.name = it->title().isEmpty() ? url.fileName() : it->title(); uris.append( uri ); @@ -160,12 +168,12 @@ void QgsStacItemItem::updateToolTip() mToolTip = QStringLiteral( "STAC Item:\n%1\n%2" ).arg( name, mPath ); } -QgsStacController *QgsStacItemItem::stacController() +QgsStacController *QgsStacItemItem::stacController() const { - QgsDataItem *item = this; + const QgsDataItem *item = this; while ( item ) { - if ( QgsStacConnectionItem *ci = qobject_cast( item ) ) + if ( const QgsStacConnectionItem *ci = qobject_cast( item ) ) return ci->controller(); item = item->parent(); } diff --git a/src/core/stac/qgsstacdataitems.h b/src/core/stac/qgsstacdataitems.h index adc460f5b64..3808b74ab80 100644 --- a/src/core/stac/qgsstacdataitems.h +++ b/src/core/stac/qgsstacdataitems.h @@ -62,7 +62,7 @@ class CORE_EXPORT QgsStacItemItem : public QgsDataItem QVariant sortKey() const override { return QStringLiteral( "2 %1" ).arg( mName ); } void updateToolTip(); - QgsStacController *stacController(); + QgsStacController *stacController() const; //! takes ownership void setStacItem( std::unique_ptr< QgsStacItem > item ); diff --git a/src/gui/stac/qgsstacdataitemguiprovider.cpp b/src/gui/stac/qgsstacdataitemguiprovider.cpp index 0976a439e82..fa552934be7 100644 --- a/src/gui/stac/qgsstacdataitemguiprovider.cpp +++ b/src/gui/stac/qgsstacdataitemguiprovider.cpp @@ -163,10 +163,12 @@ void QgsStacDataItemGuiProvider::loadConnections( QgsDataItem *item ) void QgsStacDataItemGuiProvider::showDetails( QgsDataItem *item ) { QgsStacObject *obj = nullptr; + QString authcfg; if ( QgsStacItemItem *itemItem = qobject_cast( item ) ) { obj = itemItem->stacItem(); + authcfg = itemItem->stacController()->authCfg(); } else if ( QgsStacCatalogItem *catalogItem = qobject_cast( item ) ) { @@ -176,6 +178,7 @@ void QgsStacDataItemGuiProvider::showDetails( QgsDataItem *item ) if ( obj ) { QgsStacObjectDetailsDialog d; + d.setAuthcfg( authcfg ); d.setStacObject( obj ); d.exec(); } diff --git a/src/gui/stac/qgsstacitemlistmodel.cpp b/src/gui/stac/qgsstacitemlistmodel.cpp index 9609559e76f..67a227eb9a7 100644 --- a/src/gui/stac/qgsstacitemlistmodel.cpp +++ b/src/gui/stac/qgsstacitemlistmodel.cpp @@ -137,7 +137,7 @@ void QgsStacItemListModel::setCollections( const QVector &c } } -void QgsStacItemListModel::addItems( const QVector &items ) +void QgsStacItemListModel::addItems( const QVector &items, const QString &authcfg ) { int nextItemIndex = mItems.count(); beginInsertRows( QModelIndex(), mItems.size(), mItems.size() + items.size() - 1 ); @@ -153,11 +153,15 @@ void QgsStacItemListModel::addItems( const QVector &items ) { const QString href = it->href(); QgsNetworkContentFetcher *f = new QgsNetworkContentFetcher(); - f->fetchContent( href ); + f->fetchContent( href, authcfg ); connect( f, &QgsNetworkContentFetcher::finished, this, [this, f, href, nextItemIndex] { if ( f->reply()->error() == QNetworkReply::NoError ) { - const QImage img = QImage::fromData( f->reply()->readAll() ); + const QByteArray data = f->reply()->readAll(); + const QImage img = QImage::fromData( data ); + if ( img.isNull() ) + return; + QImage previewImage( img.size(), QImage::Format_ARGB32 ); previewImage.fill( Qt::transparent ); QPainter previewPainter( &previewImage ); diff --git a/src/gui/stac/qgsstacitemlistmodel.h b/src/gui/stac/qgsstacitemlistmodel.h index 6cf066909dd..8d8a9697e14 100644 --- a/src/gui/stac/qgsstacitemlistmodel.h +++ b/src/gui/stac/qgsstacitemlistmodel.h @@ -54,7 +54,7 @@ class QgsStacItemListModel : public QAbstractListModel //! Builds collection dictionary. Does not take ownership void setCollections( const QVector &collections ); //! Add items to the model. Takes ownership - void addItems( const QVector &items ); + void addItems( const QVector &items, const QString &authcfg ); //! Returns all items in the model. Does not transfer ownership QVector items() const; diff --git a/src/gui/stac/qgsstacobjectdetailsdialog.cpp b/src/gui/stac/qgsstacobjectdetailsdialog.cpp index 12d380a8965..f70864b506d 100644 --- a/src/gui/stac/qgsstacobjectdetailsdialog.cpp +++ b/src/gui/stac/qgsstacobjectdetailsdialog.cpp @@ -18,6 +18,8 @@ #include "qgsgui.h" #include "qgsapplication.h" #include "qgsstacitem.h" +#include "qgsauthmanager.h" + #include ///@cond PRIVATE @@ -42,7 +44,16 @@ void QgsStacObjectDetailsDialog::setStacObject( QgsStacObject *stacObject ) { if ( it->roles().contains( QLatin1String( "thumbnail" ) ) ) { - thumbnails.append( QStringLiteral( "
" ).arg( it->href() ) ); + QString uri = it->href(); + if ( !mAuthcfg.isEmpty() ) + { + QStringList connectionItems; + connectionItems << uri; + QgsApplication::authManager()->updateDataSourceUriItems( connectionItems, mAuthcfg ); + uri = connectionItems.first(); + } + + thumbnails.append( QStringLiteral( "
" ).arg( uri ) ); } } } @@ -60,4 +71,9 @@ void QgsStacObjectDetailsDialog::setStacObject( QgsStacObject *stacObject ) mWebView->setHtml( html ); } +void QgsStacObjectDetailsDialog::setAuthcfg( const QString &authcfg ) +{ + mAuthcfg = authcfg; +} + ///@endcond diff --git a/src/gui/stac/qgsstacobjectdetailsdialog.h b/src/gui/stac/qgsstacobjectdetailsdialog.h index 9f831fac594..e37e1d58342 100644 --- a/src/gui/stac/qgsstacobjectdetailsdialog.h +++ b/src/gui/stac/qgsstacobjectdetailsdialog.h @@ -32,6 +32,11 @@ class QgsStacObjectDetailsDialog : public QDialog, private Ui::QgsStacObjectDeta explicit QgsStacObjectDetailsDialog( QWidget *parent = nullptr ); void setStacObject( QgsStacObject *stacObject ); + + void setAuthcfg( const QString &authcfg ); + + private: + QString mAuthcfg; }; ///@endcond diff --git a/src/gui/stac/qgsstacsourceselect.cpp b/src/gui/stac/qgsstacsourceselect.cpp index 6ad7942445e..2c7767c4809 100644 --- a/src/gui/stac/qgsstacsourceselect.cpp +++ b/src/gui/stac/qgsstacsourceselect.cpp @@ -73,7 +73,7 @@ QgsStacSourceSelect::QgsStacSourceSelect( QWidget *parent, Qt::WindowFlags fl, Q mItemsView->setContextMenuPolicy( Qt::CustomContextMenu ); connect( mItemsView, &QListView::customContextMenuRequested, this, &QgsStacSourceSelect::showItemsContextMenu ); - connect( mItemsView, &QListView::doubleClicked, this, &QgsStacSourceSelect::onItemDoubleClicked ); + connect( mItemsView, &QListView::doubleClicked, this, &QgsStacSourceSelect::showItemDetails ); connect( mItemsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsStacSourceSelect::onCurrentItemChanged ); connect( mItemsView->verticalScrollBar(), &QScrollBar::valueChanged, this, &QgsStacSourceSelect::onItemsViewScroll ); @@ -138,9 +138,10 @@ void QgsStacSourceSelect::onItemsViewScroll( int value ) } } -void QgsStacSourceSelect::onItemDoubleClicked( const QModelIndex &index ) +void QgsStacSourceSelect::showItemDetails( const QModelIndex &index ) { QgsStacObjectDetailsDialog details( this ); + details.setAuthcfg( mStac->authCfg() ); details.setStacObject( index.data( QgsStacItemListModel::Role::StacObject ).value() ); details.exec(); } @@ -372,7 +373,7 @@ void QgsStacSourceSelect::onItemCollectionRequestFinished( int requestId, QStrin mNextPageUrl = col->nextUrl(); const QVector items = col->takeItems(); - mItemsModel->addItems( items ); + mItemsModel->addItems( items, mStac->authCfg() ); for ( QgsStacItem *i : items ) { @@ -565,9 +566,7 @@ void QgsStacSourceSelect::showItemsContextMenu( QPoint point ) QAction *detailsAction = new QAction( tr( "Details…" ), menu ); connect( detailsAction, &QAction::triggered, this, [this, index] { - QgsStacObjectDetailsDialog details( this ); - details.setStacObject( index.data( QgsStacItemListModel::Role::StacObject ).value() ); - details.exec(); + showItemDetails( index ); } ); @@ -623,19 +622,26 @@ void QgsStacSourceSelect::showFootprints( bool enable ) void QgsStacSourceSelect::loadUri( const QgsMimeDataUtils::Uri &uri ) { + QString layerUri = uri.uri; + const QString authcfg = mStac->authCfg(); + if ( !authcfg.isEmpty() ) + { + layerUri += QStringLiteral( " authcfg='%1'" ).arg( authcfg ); + } + if ( uri.layerType == QLatin1String( "raster" ) ) { Q_NOWARN_DEPRECATED_PUSH - emit addRasterLayer( uri.uri, uri.name, uri.providerKey ); + emit addRasterLayer( layerUri, uri.name, uri.providerKey ); Q_NOWARN_DEPRECATED_POP - emit addLayer( Qgis::LayerType::Raster, uri.uri, uri.name, uri.providerKey ); + emit addLayer( Qgis::LayerType::Raster, layerUri, uri.name, uri.providerKey ); } else if ( uri.layerType == QLatin1String( "pointcloud" ) ) { Q_NOWARN_DEPRECATED_PUSH - emit addPointCloudLayer( uri.uri, uri.name, uri.providerKey ); + emit addPointCloudLayer( layerUri, uri.name, uri.providerKey ); Q_NOWARN_DEPRECATED_POP - emit addLayer( Qgis::LayerType::PointCloud, uri.uri, uri.name, uri.providerKey ); + emit addLayer( Qgis::LayerType::PointCloud, layerUri, uri.name, uri.providerKey ); } } ///@endcond diff --git a/src/gui/stac/qgsstacsourceselect.h b/src/gui/stac/qgsstacsourceselect.h index d0e4ec4dd69..6b5a5532fff 100644 --- a/src/gui/stac/qgsstacsourceselect.h +++ b/src/gui/stac/qgsstacsourceselect.h @@ -82,7 +82,7 @@ class GUI_EXPORT QgsStacSourceSelect : public QgsAbstractDataSourceWidget, priva void onItemsViewScroll( int value ); //! Called when double clicking a result item - void onItemDoubleClicked( const QModelIndex &index ); + void showItemDetails( const QModelIndex &index ); //! Enables Add Layers button based on current item, updates rubber bands void onCurrentItemChanged( const QModelIndex ¤t, const QModelIndex &previous );