Refactor out method for creating layer data items from file-like paths

Provide a method so that external classes can use this same logic
to create their own layer items containing sublayers for file-like
paths.
This commit is contained in:
Nyall Dawson 2024-06-25 13:04:19 +10:00
parent b733307109
commit 392eaac69a
2 changed files with 103 additions and 8 deletions

View File

@ -213,9 +213,10 @@ QgsMimeDataUtils::UriList QgsFileDataCollectionGroupItem::mimeUris() const
// QgsFileDataCollectionItem
//
QgsFileDataCollectionItem::QgsFileDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path, const QList<QgsProviderSublayerDetails> &sublayers )
QgsFileDataCollectionItem::QgsFileDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path, const QList<QgsProviderSublayerDetails> &sublayers, const QVariantMap &extraUriParts )
: QgsDataCollectionItem( parent, name, path )
, mSublayers( sublayers )
, mExtraUriParts( extraUriParts )
{
if ( QgsProviderUtils::sublayerDetailsAreIncomplete( mSublayers, QgsProviderUtils::SublayerCompletenessFlag::IgnoreUnknownFeatureCount ) )
setCapabilities( Qgis::BrowserItemCapability::Fertile );
@ -231,8 +232,37 @@ QgsFileDataCollectionItem::QgsFileDataCollectionItem( QgsDataItem *parent, const
QVector<QgsDataItem *> QgsFileDataCollectionItem::createChildren()
{
QList< QgsProviderSublayerDetails> sublayers;
if ( QgsProviderUtils::sublayerDetailsAreIncomplete( mSublayers, QgsProviderUtils::SublayerCompletenessFlag::IgnoreUnknownFeatureCount )
|| mSublayers.empty() )
if ( QgsProviderUtils::sublayerDetailsAreIncomplete( mSublayers, QgsProviderUtils::SublayerCompletenessFlag::IgnoreUnknownFeatureCount ) )
{
QSet< QString > providers;
for ( const QgsProviderSublayerDetails &details : std::as_const( mSublayers ) )
{
providers.insert( details.providerKey() );
}
for ( const QString &provider : std::as_const( providers ) )
{
if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( provider ) )
{
if ( !mExtraUriParts.empty() )
{
QVariantMap uriParts = metadata->decodeUri( path() );
for ( auto it = mExtraUriParts.constBegin(); it != mExtraUriParts.constEnd(); ++it )
{
uriParts.insert( it.key(), it.value() );
}
QString updatedUri = metadata->encodeUri( uriParts );
sublayers.append( metadata->querySublayers( updatedUri.isEmpty() ? path() : updatedUri, Qgis::SublayerQueryFlag::ResolveGeometryType ) );
}
else
{
sublayers.append( metadata->querySublayers( path(), Qgis::SublayerQueryFlag::ResolveGeometryType ) );
}
}
}
}
else if ( mSublayers.empty() )
{
sublayers = QgsProviderRegistry::instance()->querySublayers( path(), Qgis::SublayerQueryFlag::ResolveGeometryType );
}
@ -526,6 +556,16 @@ Qgis::DataItemProviderCapabilities QgsFileBasedDataItemProvider::capabilities()
}
QgsDataItem *QgsFileBasedDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
{
return createDataItemForPathPrivate( path, parentItem, nullptr, Qgis::SublayerQueryFlags(), QVariantMap() );
}
QgsDataItem *QgsFileBasedDataItemProvider::createLayerItemForPath( const QString &path, QgsDataItem *parentItem, const QStringList &allowedProviders, const QVariantMap &extraUriParts, Qgis::SublayerQueryFlags queryFlags )
{
return createDataItemForPathPrivate( path, parentItem, &allowedProviders, queryFlags, extraUriParts );
}
QgsDataItem *QgsFileBasedDataItemProvider::createDataItemForPathPrivate( const QString &path, QgsDataItem *parentItem, const QStringList *allowedProviders, Qgis::SublayerQueryFlags queryFlags, const QVariantMap &extraUriParts )
{
if ( path.isEmpty() )
return nullptr;
@ -579,8 +619,6 @@ QgsDataItem *QgsFileBasedDataItemProvider::createDataItem( const QString &path,
QgsSettings settings;
Qgis::SublayerQueryFlags queryFlags = Qgis::SublayerQueryFlags();
// should we fast scan only?
if ( ( settings.value( QStringLiteral( "qgis/scanItemsInBrowser2" ),
"extension" ).toString() == QLatin1String( "extension" ) ) ||
@ -590,7 +628,34 @@ QgsDataItem *QgsFileBasedDataItemProvider::createDataItem( const QString &path,
queryFlags |= Qgis::SublayerQueryFlag::FastScan;
}
const QList<QgsProviderSublayerDetails> sublayers = QgsProviderRegistry::instance()->querySublayers( path, queryFlags );
QList<QgsProviderSublayerDetails> sublayers;
if ( !allowedProviders )
{
sublayers = QgsProviderRegistry::instance()->querySublayers( path, queryFlags );
}
else
{
for ( const QString &provider : *allowedProviders )
{
if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( provider ) )
{
if ( !extraUriParts.empty() )
{
QVariantMap uriParts = metadata->decodeUri( path );
for ( auto it = extraUriParts.constBegin(); it != extraUriParts.constEnd(); ++it )
{
uriParts.insert( it.key(), it.value() );
}
sublayers.append( metadata->querySublayers( metadata->encodeUri( uriParts ), queryFlags ) );
}
else
{
sublayers.append( metadata->querySublayers( path, queryFlags ) );
}
}
}
}
if ( sublayers.size() == 1
&& ( ( ( queryFlags & Qgis::SublayerQueryFlag::FastScan ) && !QgsProviderUtils::sublayerDetailsAreIncomplete( sublayers, QgsProviderUtils::SublayerCompletenessFlag::IgnoreUnknownFeatureCount | QgsProviderUtils::SublayerCompletenessFlag::IgnoreUnknownGeometryType ) )
@ -603,7 +668,7 @@ QgsDataItem *QgsFileBasedDataItemProvider::createDataItem( const QString &path,
}
else if ( !sublayers.empty() )
{
QgsFileDataCollectionItem *item = new QgsFileDataCollectionItem( parentItem, name, path, sublayers );
QgsFileDataCollectionItem *item = new QgsFileDataCollectionItem( parentItem, name, path, sublayers, extraUriParts );
item->setCapabilities( item->capabilities2() | Qgis::BrowserItemCapability::ItemRepresentsFile );
return item;
}

View File

@ -129,8 +129,13 @@ class CORE_EXPORT QgsFileDataCollectionItem final: public QgsDataCollectionItem
* \param sublayers list of sublayers to initially populate the item with. If the sublayer details are incomplete
* (see QgsProviderUtils::sublayerDetailsAreIncomplete()) then the item will be populated in a background thread when
* expanded.
* \param extraUriParts optional map of extra components to append to URIs generated for the \a path. The provider-specific encodeUri methods will be used to handle these URI additions. Since QGIS 3.40.
*/
QgsFileDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path, const QList< QgsProviderSublayerDetails> &sublayers );
QgsFileDataCollectionItem( QgsDataItem *parent,
const QString &name,
const QString &path,
const QList< QgsProviderSublayerDetails> &sublayers,
const QVariantMap &extraUriParts = QVariantMap() );
QVector<QgsDataItem *> createChildren() override;
bool hasDragEnabled() const override;
@ -180,6 +185,7 @@ class CORE_EXPORT QgsFileDataCollectionItem final: public QgsDataCollectionItem
private:
QList< QgsProviderSublayerDetails> mSublayers;
QVariantMap mExtraUriParts;
mutable bool mHasCachedCapabilities = false;
mutable QgsAbstractDatabaseProviderConnection::Capabilities mCachedCapabilities;
mutable Qgis::DatabaseProviderConnectionCapabilities2 mCachedCapabilities2;
@ -204,7 +210,31 @@ class CORE_EXPORT QgsFileBasedDataItemProvider : public QgsDataItemProvider
QString name() override;
Qgis::DataItemProviderCapabilities capabilities() const override;
QgsDataItem *createDataItem( const QString &path, QgsDataItem *parentItem ) override SIP_FACTORY;
/**
* Static method to create a data item for sublayers corresponding to a file-like \a path.
*
* \param path file like path to create item for
* \param parentItem parent data item
* \param providers list of data providers to include when scanning for sublayers for the path. Must be populated.
* \param extraUriParts map of optional extra components to append to URIs generated for the \a path. The provider-specific encodeUri methods will be used to handle these URI additions.
* \param queryFlags flags controlling sublayer querying
*
* \returns data item, if \a path corresponds to a layer or an item with multiple sublayers
*
* \since QGIS 3.40
*/
static QgsDataItem *createLayerItemForPath( const QString &path, QgsDataItem *parentItem, const QStringList &providers,
const QVariantMap &extraUriParts,
Qgis::SublayerQueryFlags queryFlags );
bool handlesDirectoryPath( const QString &path ) override;
private:
static QgsDataItem *createDataItemForPathPrivate( const QString &path, QgsDataItem *parentItem, const QStringList *allowedProviders,
Qgis::SublayerQueryFlags queryFlags,
const QVariantMap &extraUriParts );
};
#endif // QGSFILEBASEDDATAITEMPROVIDER_H