Skip to content

Conversation

captaincoordinates
Copy link
Contributor

Description

Closes #62838

Incorporates the following changes.

sip

Updated sip.in files by running sipify_all.sh script (which generates some changes not directly triggered by this change).

Cloud-Optimised

Recognised Zarr as a cloud-optimised media type in QgsStacAsset logic and added Zarr handling logic in the uri function to correctly prefix STAC Asset hrefs with ZARR:/vsicurl/ so that Zarr STAC Assets can be added as layers.

qgis-stac-asset-drag-drop-layer

Assets in Browser Pane

Added a further nesting beneath STAC Items in the Browser pane showing assets. This allows individual cloud-optimised STAC Assets to be drag-dropped into the Layers pane. Previously only STAC Items could be drag-dropped into the Layers pane if they contained at least one cloud-optimised STAC Asset, at which point all of the STAC Item's cloud-optimised STAC Assets were added to the Layers pane. This change adds greater flexibility and better supports STAC Items with many cloud-optimised STAC Assets.

qgis-stac-assets-with-tooltip

Note

As part of this change logic to generate HTML representations of STAC Assets for STAC Items' Details modal was extracted to a separate function so that individual STAC Assets can have their own Details modal.

qgis-stac-asset-details

Downloadable Assets

Added QgsStacAsset::isDownloadable to determine if assets should provide a download option. Zarr assets should not be offered for download as the STAC Asset's href points to a directory rather than a data file or archive. Zarr download attempts in QGIS will either fail with 4xx or download a directory listing response.

qgis-stac-item-downloadable-assets

DRY

Removed duplication in STAC Asset handling logic.

Note

Prior to this change logic in the QgsStacAsset class was duplicated in QgsStacItemItem and this change includes a DRY consolidation. The QgsStacAsset class's formatName function and uri function were effecitvely duplicated in the QgsStacItemItem class's mimeUris function. The QgsStacItemItem has been changed to reference the consolidated logic. Commit fa4192dbe9bda7c4aa721500ca9f8ca0523abaa6 added auth handling to QgsStacItemItem::mimeUris but not to QgsStacAsset::uri. This DRY consolidation implements the same auth handling in QgsStacAsset::uri, which is why the PR shows that function being edited.

@github-actions github-actions bot added this to the 4.0.0 milestone Sep 26, 2025
@captaincoordinates
Copy link
Contributor Author

captaincoordinates commented Sep 26, 2025

I'm working on fixing the layout issues, pre-commit was not working for some of these commits

Layout issues addressed

Copy link
Contributor

github-actions bot commented Sep 26, 2025

🪟 Windows Qt6 builds

Download Windows Qt6 builds of this PR for testing.
(Built from commit 1e7e899)

🍎 MacOS Qt6 builds

Download MacOS Qt6 builds of this PR for testing.
This installer is not signed, control+click > open the app to avoid the warning
(Built from commit 1e7e899)

@captaincoordinates captaincoordinates force-pushed the 62838-zarr-co-media-type-stac-04 branch from 9a713a7 to 8c623f4 Compare September 26, 2025 22:59
Returns a uri for the asset if it is a cloud optimized file like COG or
COPC, empty auth configuration

.. versionadded:: 3.42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-kuhn I believe 3.42 is the correct version here. This .sip.in change resulted from pre-commit hooks executing on my change, though my change did not modify this function. The commit that added this function (here) did not update .sip.in files, and my change was the first time these files were updated for this behaviour. Presumably the previous author did not execute pre-commit hooks.

However - the following function, an overload of this function that accepts a QString parameter, is new and should reference 4.0. I will make this change shortly.

QString html = QStringLiteral( "<html><head></head>\n<body>\n" );

html += QStringLiteral( "<h1>%1</h1>\n<hr>\n" ).arg( QLatin1String( "Item" ) );
QString html = QStringLiteral( "<h1>%1</h1>\n<hr>\n" ).arg( QLatin1String( "Item" ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should Item be translated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-kuhn this is a good question. The previous implementation did not translate the string, and also "Item" is a specific term in the STAC specification and I am not sure if STAC intends for it to be translated.

As the string was not previously translated, and other STAC terms such as "Collection" and "Links" are not translated, my preference would be to address this question in a separate issue if necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to not translate stac entity names, at least not yet.

@captaincoordinates captaincoordinates force-pushed the 62838-zarr-co-media-type-stac-04 branch from ad157e1 to f6de369 Compare September 29, 2025 20:21
@captaincoordinates captaincoordinates force-pushed the 62838-zarr-co-media-type-stac-04 branch from f6de369 to 1e7e899 Compare September 29, 2025 20:22
@captaincoordinates
Copy link
Contributor Author

@m-kuhn thanks for your input. I've made requested changes and responded where I wasn't sure a change was necessary.


private:
QString mAuthcfg;
void setContent( QString bodyHtml, QString thumbnailHtml );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void setContent( QString bodyHtml, QString thumbnailHtml );
void setContent( const QString &bodyHtml, const QString &thumbnailHtml );

Comment on lines +22 to 23
#include "qgsstacasset.h"
#include "qgsstacobject.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's forward-declare both QgsStacAsset and QgsStacObject instead of including

Comment on lines +61 to +66
QString thumbnailHtml;
if ( isThumbnailAsset( stacAsset ) )
{
thumbnailHtml = thumbnailHtmlContent( stacAsset );
}
QString bodyHtml = stacAsset->toHtml( assetId );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
QString thumbnailHtml;
if ( isThumbnailAsset( stacAsset ) )
{
thumbnailHtml = thumbnailHtmlContent( stacAsset );
}
QString bodyHtml = stacAsset->toHtml( assetId );
const QString thumbnailHtml = isThumbnailAsset( stacAsset ) ? thumbnailHtmlContent( stacAsset ) : QString();
const QString bodyHtml = stacAsset->toHtml( assetId );

Comment on lines +53 to +54
QString thumbnailHtml = thumbnails.join( QString() );
QString bodyHtml = stacObject->toHtml();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
QString thumbnailHtml = thumbnails.join( QString() );
QString bodyHtml = stacObject->toHtml();
const QString thumbnailHtml = thumbnails.join( QString() );
const QString bodyHtml = stacObject->toHtml();

QAction *actionDownload = new QAction( tr( "Download Assets…" ), menu );
connect( actionDownload, &QAction::triggered, this, [itemItem, context] { downloadAssets( itemItem, context ); } );
menu->addAction( actionDownload );
int downloadableAssets = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace the int with a bool hasDownloadableAssets and break the iteration at first downloadable asset occurrance

QString html = QStringLiteral( "<html><head></head>\n<body>\n" );

html += QStringLiteral( "<h1>%1</h1>\n<hr>\n" ).arg( QLatin1String( "Item" ) );
QString html = QStringLiteral( "<h1>%1</h1>\n<hr>\n" ).arg( QLatin1String( "Item" ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to not translate stac entity names, at least not yet.

mStacAsset( asset ),
mName( name )
{
mIconName = QStringLiteral( "mActionPropertiesWidget.svg" );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a separate icon for assets

Comment on lines +526 to +527
// create any assets beneath the item, so that they can be individually drag-dropped as layers if compatible
i->populate( true );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why pre populate all assets for all items?
Should we not wait for the user to expand the Item?

bool hasDragEnabled() const override;
QgsMimeDataUtils::UriList mimeUris() const override;
bool equal( const QgsDataItem *other ) override;
QVariant sortKey() const override { return QStringLiteral( "4 %1" ).arg( mName ); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if 4 might cause some unexpected sorting as the QgsStacFetchMoreItem which should always be last, has 3 as a sort key.

Comment on lines +81 to +85
/**
* Returns a uri for the asset if it is a cloud optimized file like COG or COPC
* \since QGIS 4.0
*/
QgsMimeDataUtils::Uri uri( const QString &authcfg ) const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think QgsStacAsset should have such method. This class should just be a container class for the stac asset properties.
It would be the caller's responsibility to add the authcfg to the URI based on the provider (the current approach of just appending authcfg=... is a bit naive).
Maybe something like:

QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( uri.providerKey );
QVariantMap map = md->decodeUri( uri.uri );
map[ QStringLiteral( "authcfg" ) ] = authcfg;
uri.uri = md.encodeUri( map );

??
Maybe it could be a void QgsMimeDataUtils::Uri::setAuthCfg( const QString &authcfg );?
What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Zarr as a Cloud-Optimised Media Type in STAC
3 participants