Skip to content

Commit

Permalink
Correctly handle GDAL drivers which support BOTH raster and vector
Browse files Browse the repository at this point in the history
layers in the GDAL driver list in options dialog
(cherry picked from commit 0f91d38)

Ensure entries for the same raster/vector driver always keep their check states in sync with each other
(cherry picked from commit c1e75bd)
  • Loading branch information
agiudiceandrea authored and nyalldawson committed Sep 22, 2023
1 parent 069667e commit 5c423ab
Showing 1 changed file with 76 additions and 34 deletions.
110 changes: 76 additions & 34 deletions src/app/options/qgsoptions.cpp
Expand Up @@ -138,6 +138,35 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QList<QgsOpti
connect( cbxProjectDefaultNew, &QCheckBox::toggled, this, &QgsOptions::cbxProjectDefaultNew_toggled );
connect( leLayerGlobalCrs, &QgsProjectionSelectionWidget::crsChanged, this, &QgsOptions::leLayerGlobalCrs_crsChanged );
connect( lstRasterDrivers, &QTreeWidget::itemDoubleClicked, this, &QgsOptions::lstRasterDrivers_itemDoubleClicked );

// some drivers apply for both raster and vector -- we treat these as siblings
// and must ensure that checking/unchecking one also checks/unchecks the other
// (we can't selectively just disable the raster/vector part of a GDAL driver)
auto syncItem = [ = ]( QTreeWidgetItem * changedItem, QTreeWidget * otherTree )
{
const QString driver = changedItem->data( 0, Qt::UserRole ).toString();
for ( int i = 0; i < otherTree->topLevelItemCount(); ++ i )
{
if ( QTreeWidgetItem *otherItem = otherTree->topLevelItem( i ) )
{
const QString otherDriver = otherItem->data( 0, Qt::UserRole ).toString();
if ( otherDriver == driver )
{
otherItem->setCheckState( 0, changedItem->checkState( 0 ) );
return;
}
}
}
};
connect( lstRasterDrivers, &QTreeWidget::itemChanged, this, [ = ]( QTreeWidgetItem * item, int )
{
syncItem( item, lstVectorDrivers );
} );
connect( lstVectorDrivers, &QTreeWidget::itemChanged, this, [ = ]( QTreeWidgetItem * item, int )
{
syncItem( item, lstRasterDrivers );
} );

connect( mProjectOnLaunchCmbBx, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsOptions::mProjectOnLaunchCmbBx_currentIndexChanged );
connect( spinFontSize, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsOptions::spinFontSize_valueChanged );
connect( mFontFamilyRadioQt, &QRadioButton::released, this, &QgsOptions::mFontFamilyRadioQt_released );
Expand Down Expand Up @@ -2260,8 +2289,10 @@ void QgsOptions::loadGdalDriverList()
QString myGdalDriverDescription;
QStringList myDrivers;
QStringList myGdalWriteDrivers;
QMap<QString, QString> myDriversFlags, myDriversExt, myDriversLongName;
QMap<QString, QgsMapLayerType> driversType;
QMap<QString, QString> rasterDriversFlags;
QMap<QString, QString> vectorDriversFlags;
QMap<QString, QString> myDriversExt, myDriversLongName;
QMap<QString, QSet< int >> driversType;

// make sure we save list when accept()
mLoadedGdalDriverList = true;
Expand All @@ -2288,19 +2319,19 @@ void QgsOptions::loadGdalDriverList()
myDrivers << myGdalDriverDescription;
if ( QString( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_RASTER, nullptr ) ) == QLatin1String( "YES" ) )
{
driversType[myGdalDriverDescription] = QgsMapLayerType::RasterLayer;
driversType[myGdalDriverDescription].insert( static_cast< int >( QgsMapLayerType::RasterLayer ) );
}
else if ( QString( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VECTOR, nullptr ) ) == QLatin1String( "YES" ) )
if ( QString( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VECTOR, nullptr ) ) == QLatin1String( "YES" ) )
{
driversType[myGdalDriverDescription] = QgsMapLayerType::VectorLayer;
driversType[myGdalDriverDescription].insert( static_cast< int >( QgsMapLayerType::VectorLayer ) );
}

QgsDebugMsgLevel( QStringLiteral( "driver #%1 - %2" ).arg( i ).arg( myGdalDriverDescription ), 2 );

// get driver R/W flags, adopted from GDALGeneralCmdLineProcessor()
QString driverFlags = "";
if ( driversType[myGdalDriverDescription] == QgsMapLayerType::RasterLayer )
if ( driversType.value( myGdalDriverDescription ).contains( static_cast< int >( QgsMapLayerType::RasterLayer ) ) )
{
QString driverFlags = "";
if ( QgsGdalUtils::supportsRasterCreate( myGdalDriver ) )
{
myGdalWriteDrivers << myGdalDriverDescription;
Expand All @@ -2311,9 +2342,15 @@ void QgsOptions::loadGdalDriverList()
driverFlags = "rw";
else
driverFlags = "ro";

if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VIRTUALIO, nullptr ) )
driverFlags += "v";

rasterDriversFlags[myGdalDriverDescription] = driverFlags;
}
else
if ( driversType.value( myGdalDriverDescription ).contains( static_cast< int >( QgsMapLayerType::VectorLayer ) ) )
{
QString driverFlags = "";
if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_OPEN, nullptr ) )
driverFlags = "r";

Expand All @@ -2323,20 +2360,20 @@ void QgsOptions::loadGdalDriverList()
driverFlags += "w";
else
driverFlags += "o";
}

if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VIRTUALIO, nullptr ) )
driverFlags += "v";
if ( GDALGetMetadataItem( myGdalDriver, GDAL_DCAP_VIRTUALIO, nullptr ) )
driverFlags += "v";

myDriversFlags[myGdalDriverDescription] = driverFlags;
vectorDriversFlags[myGdalDriverDescription] = driverFlags;
}

// get driver extensions and long name
// the gdal provider can override/add extensions but there is no interface to query this
// aside from parsing QgsRasterLayer::buildSupportedRasterFileFilter()
myDriversExt[myGdalDriverDescription] = QString( GDALGetMetadataItem( myGdalDriver, "DMD_EXTENSION", "" ) ).toLower();
myDriversLongName[myGdalDriverDescription] = QString( GDALGetMetadataItem( myGdalDriver, "DMD_LONGNAME", "" ) );

}

// restore active drivers
QgsApplication::applyGdalSkippedDrivers();

Expand All @@ -2349,30 +2386,35 @@ void QgsOptions::loadGdalDriverList()
strMap.insert( str.toLower(), str );
myDrivers = strMap.values();

for ( const QString &myName : std::as_const( myDrivers ) )
for ( const QString &driverName : std::as_const( myDrivers ) )
{
QTreeWidgetItem *mypItem = new QTreeWidgetItem( QStringList( myName ) );
if ( mySkippedDrivers.contains( myName ) )
const QSet< int > layerTypes = driversType[driverName];
for ( int layerType : layerTypes )
{
mypItem->setCheckState( 0, Qt::Unchecked );
}
else
{
mypItem->setCheckState( 0, Qt::Checked );
}
QTreeWidgetItem *driverItem = new QTreeWidgetItem( QStringList( driverName ) );
if ( mySkippedDrivers.contains( driverName ) )
{
driverItem->setCheckState( 0, Qt::Unchecked );
}
else
{
driverItem->setCheckState( 0, Qt::Checked );
}

// add driver metadata
mypItem->setText( 1, myDriversExt[myName] );
QString myFlags = myDriversFlags[myName];
mypItem->setText( 2, myFlags );
mypItem->setText( 3, myDriversLongName[myName] );
if ( driversType[myName] == QgsMapLayerType::RasterLayer )
{
lstRasterDrivers->addTopLevelItem( mypItem );
}
else
{
lstVectorDrivers->addTopLevelItem( mypItem );
// add driver metadata
driverItem->setData( 0, Qt::UserRole, driverName );
driverItem->setText( 1, myDriversExt[driverName] );
const QString driverFlags = static_cast< QgsMapLayerType >( layerType ) == QgsMapLayerType::RasterLayer ? rasterDriversFlags[driverName] : vectorDriversFlags[driverName];
driverItem->setText( 2, driverFlags );
driverItem->setText( 3, myDriversLongName[driverName] );
if ( static_cast< QgsMapLayerType >( layerType ) == QgsMapLayerType::RasterLayer )
{
lstRasterDrivers->addTopLevelItem( driverItem );
}
else
{
lstVectorDrivers->addTopLevelItem( driverItem );
}
}
}

Expand Down

0 comments on commit 5c423ab

Please sign in to comment.