base path handler

This commit is contained in:
Alex 2019-03-20 20:01:50 -04:00 committed by GitHub
parent 6f92e7cf4b
commit b03d61d5d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 573 additions and 540 deletions

View File

@ -1,461 +1,493 @@
/*************************************************************************** /***************************************************************************
qgshandlebadlayers.cpp - description qgshandlebadlayers.cpp - description
------------------- -------------------
begin : Sat 5 Mar 2011 begin : Sat 5 Mar 2011
copyright : (C) 2011 by Juergen E. Fischer, norBIT GmbH copyright : (C) 2011 by Juergen E. Fischer, norBIT GmbH
email : jef at norbit dot de email : jef at norbit dot de
***************************************************************************/ ***************************************************************************/
/*************************************************************************** /***************************************************************************
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
***************************************************************************/ ***************************************************************************/
#include "qgshandlebadlayers.h" #include "qgshandlebadlayers.h"
#include "qgisapp.h" #include "qgisapp.h"
#include "qgsauthconfigselect.h" #include "qgsauthconfigselect.h"
#include "qgsdataprovider.h" #include "qgsdataprovider.h"
#include "qgsguiutils.h" #include "qgsguiutils.h"
#include "qgsdatasourceuri.h" #include "qgsdatasourceuri.h"
#include "qgslogger.h" #include "qgslogger.h"
#include "qgsrasterlayer.h" #include "qgsrasterlayer.h"
#include "qgsproviderregistry.h" #include "qgsproviderregistry.h"
#include "qgsmessagebar.h" #include "qgsmessagebar.h"
#include "qgssettings.h" #include "qgssettings.h"
#include "qgslayertreeregistrybridge.h" #include "qgslayertreeregistrybridge.h"
#include "qgsapplication.h" #include "qgsapplication.h"
#include <QDomDocument> #include <QDomDocument>
#include <QDomElement> #include <QDomElement>
#include <QFileDialog> #include <QFileDialog>
#include <QPushButton> #include <QPushButton>
#include <QToolButton> #include <QToolButton>
#include <QMessageBox> #include <QMessageBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QUrl> #include <QUrl>
void QgsHandleBadLayersHandler::handleBadLayers( const QList<QDomNode> &layers ) void QgsHandleBadLayersHandler::handleBadLayers( const QList<QDomNode> &layers )
{ {
QApplication::setOverrideCursor( Qt::ArrowCursor ); QApplication::setOverrideCursor( Qt::ArrowCursor );
QgsHandleBadLayers *dialog = new QgsHandleBadLayers( layers ); QgsHandleBadLayers *dialog = new QgsHandleBadLayers( layers );
dialog->buttonBox->button( QDialogButtonBox::Ignore )->setToolTip( tr( "Import all unavailable layers unmodified (you can fix them later)." ) ); dialog->buttonBox->button( QDialogButtonBox::Ignore )->setToolTip( tr( "Import all unavailable layers unmodified (you can fix them later)." ) );
dialog->buttonBox->button( QDialogButtonBox::Ignore )->setText( tr( "Keep Unavailable Layers" ) ); dialog->buttonBox->button( QDialogButtonBox::Ignore )->setText( tr( "Keep Unavailable Layers" ) );
dialog->buttonBox->button( QDialogButtonBox::Discard )->setToolTip( tr( "Remove all unavailable layers from the project" ) ); dialog->buttonBox->button( QDialogButtonBox::Discard )->setToolTip( tr( "Remove all unavailable layers from the project" ) );
dialog->buttonBox->button( QDialogButtonBox::Discard )->setText( tr( "Remove Unavailable Layers" ) ); dialog->buttonBox->button( QDialogButtonBox::Discard )->setText( tr( "Remove Unavailable Layers" ) );
dialog->buttonBox->button( QDialogButtonBox::Discard )->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ) ); dialog->buttonBox->button( QDialogButtonBox::Discard )->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ) );
if ( dialog->layerCount() < layers.size() ) if ( dialog->layerCount() < layers.size() )
QgisApp::instance()->messageBar()->pushMessage( QgisApp::instance()->messageBar()->pushMessage(
tr( "Handle unavailable layers" ), tr( "Handle unavailable layers" ),
tr( "%1 of %2 unavailable layers were not fixable." ) tr( "%1 of %2 unavailable layers were not fixable." )
.arg( layers.size() - dialog->layerCount() ) .arg( layers.size() - dialog->layerCount() )
.arg( layers.size() ), .arg( layers.size() ),
Qgis::Warning, QgisApp::instance()->messageTimeout() ); Qgis::Warning, QgisApp::instance()->messageTimeout() );
if ( dialog->layerCount() > 0 ) if ( dialog->layerCount() > 0 )
{ {
if ( dialog->exec() == dialog->Accepted ) if ( dialog->exec() == dialog->Accepted )
{ {
emit layersChanged(); emit layersChanged();
} }
} }
delete dialog; delete dialog;
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
} }
QgsHandleBadLayers::QgsHandleBadLayers( const QList<QDomNode> &layers ) QgsHandleBadLayers::QgsHandleBadLayers( const QList<QDomNode> &layers )
: QDialog( QgisApp::instance() ) : QDialog( QgisApp::instance() )
, mLayers( layers ) , mLayers( layers )
{ {
setupUi( this ); setupUi( this );
mVectorFileFilter = QgsProviderRegistry::instance()->fileVectorFilters(); mVectorFileFilter = QgsProviderRegistry::instance()->fileVectorFilters();
mRasterFileFilter = QgsProviderRegistry::instance()->fileRasterFilters(); mRasterFileFilter = QgsProviderRegistry::instance()->fileRasterFilters();
mBrowseButton = new QPushButton( tr( "Browse" ) ); mBrowseButton = new QPushButton( tr( "Browse" ) );
buttonBox->addButton( mBrowseButton, QDialogButtonBox::ActionRole ); buttonBox->addButton( mBrowseButton, QDialogButtonBox::ActionRole );
mBrowseButton->setDisabled( true ); mBrowseButton->setDisabled( true );
mApplyButton = new QPushButton( tr( "Apply Changes" ) ); mApplyButton = new QPushButton( tr( "Apply Changes" ) );
mApplyButton->setToolTip( tr( "Apply fixes to unavailable layers (remaining unavailable layers will be removed from the project)." ) ); mApplyButton->setToolTip( tr( "Apply fixes to unavailable layers (remaining unavailable layers will be removed from the project)." ) );
buttonBox->addButton( mApplyButton, QDialogButtonBox::ActionRole ); buttonBox->addButton( mApplyButton, QDialogButtonBox::ActionRole );
connect( mLayerList, &QTableWidget::itemSelectionChanged, this, &QgsHandleBadLayers::selectionChanged ); connect( mLayerList, &QTableWidget::itemSelectionChanged, this, &QgsHandleBadLayers::selectionChanged );
connect( mBrowseButton, &QAbstractButton::clicked, this, &QgsHandleBadLayers::browseClicked ); connect( mBrowseButton, &QAbstractButton::clicked, this, &QgsHandleBadLayers::browseClicked );
connect( mApplyButton, &QAbstractButton::clicked, this, &QgsHandleBadLayers::apply ); connect( mApplyButton, &QAbstractButton::clicked, this, &QgsHandleBadLayers::apply );
connect( buttonBox->button( QDialogButtonBox::Ignore ), &QPushButton::clicked, this, &QgsHandleBadLayers::reject ); connect( buttonBox->button( QDialogButtonBox::Ignore ), &QPushButton::clicked, this, &QgsHandleBadLayers::reject );
connect( buttonBox->button( QDialogButtonBox::Discard ), &QPushButton::clicked, this, &QgsHandleBadLayers::accept ); connect( buttonBox->button( QDialogButtonBox::Discard ), &QPushButton::clicked, this, &QgsHandleBadLayers::accept );
mLayerList->clear(); mLayerList->clear();
mLayerList->setSortingEnabled( true ); mLayerList->setSortingEnabled( true );
mLayerList->setSelectionBehavior( QAbstractItemView::SelectRows ); mLayerList->setSelectionBehavior( QAbstractItemView::SelectRows );
mLayerList->setColumnCount( 5 ); mLayerList->setColumnCount( 5 );
mLayerList->setColumnWidth( 3, 75 ); mLayerList->setColumnWidth( 3, 75 );
mLayerList->setHorizontalHeaderLabels( QStringList() mLayerList->setHorizontalHeaderLabels( QStringList()
<< tr( "Layer name" ) << tr( "Layer name" )
<< tr( "Type" ) << tr( "Type" )
<< tr( "Provider" ) << tr( "Provider" )
<< tr( "Auth config" ) << tr( "Auth config" )
<< tr( "Datasource" ) << tr( "Datasource" )
); );
int j = 0; int j = 0;
for ( int i = 0; i < mLayers.size(); i++ ) for ( int i = 0; i < mLayers.size(); i++ )
{ {
const QDomNode &node = mLayers[i]; const QDomNode &node = mLayers[i];
QString name = node.namedItem( QStringLiteral( "layername" ) ).toElement().text(); QString name = node.namedItem( QStringLiteral( "layername" ) ).toElement().text();
QString type = node.toElement().attribute( QStringLiteral( "type" ) ); QString type = node.toElement().attribute( QStringLiteral( "type" ) );
QString datasource = node.namedItem( QStringLiteral( "datasource" ) ).toElement().text(); QString datasource = node.namedItem( QStringLiteral( "datasource" ) ).toElement().text();
QString provider = node.namedItem( QStringLiteral( "provider" ) ).toElement().text(); QString provider = node.namedItem( QStringLiteral( "provider" ) ).toElement().text();
QString vectorProvider = type == QLatin1String( "vector" ) ? provider : tr( "none" ); QString vectorProvider = type == QLatin1String( "vector" ) ? provider : tr( "none" );
bool providerFileBased = ( QgsProviderRegistry::instance()->providerCapabilities( provider ) & QgsDataProvider::File ) != 0; bool providerFileBased = ( QgsProviderRegistry::instance()->providerCapabilities( provider ) & QgsDataProvider::File ) != 0;
QgsDebugMsg( QStringLiteral( "name=%1 type=%2 provider=%3 datasource='%4'" ) mFileBase[name].append( const datasource.left( datasource.lastIndexOf('/') ) );
.arg( name,
type, QgsDebugMsg( QStringLiteral( "name=%1 type=%2 provider=%3 datasource='%4'" )
vectorProvider, .arg( name,
datasource ) ); type,
vectorProvider,
mLayerList->setRowCount( j + 1 ); datasource ) );
QTableWidgetItem *item = nullptr; mLayerList->setRowCount( j + 1 );
item = new QTableWidgetItem( name ); QTableWidgetItem *item = nullptr;
item->setData( Qt::UserRole + 0, i );
item->setFlags( item->flags() & ~Qt::ItemIsEditable ); item = new QTableWidgetItem( name );
mLayerList->setItem( j, 0, item ); item->setData( Qt::UserRole + 0, i );
item->setFlags( item->flags() & ~Qt::ItemIsEditable );
item = new QTableWidgetItem( type ); mLayerList->setItem( j, 0, item );
item->setData( Qt::UserRole + 0, providerFileBased );
item->setFlags( item->flags() & ~Qt::ItemIsEditable ); item = new QTableWidgetItem( type );
mLayerList->setItem( j, 1, item ); item->setData( Qt::UserRole + 0, providerFileBased );
item->setFlags( item->flags() & ~Qt::ItemIsEditable );
item = new QTableWidgetItem( vectorProvider ); mLayerList->setItem( j, 1, item );
item->setFlags( item->flags() & ~Qt::ItemIsEditable );
mLayerList->setItem( j, 2, item ); item = new QTableWidgetItem( vectorProvider );
item->setFlags( item->flags() & ~Qt::ItemIsEditable );
if ( QgsAuthConfigUriEdit::hasConfigId( datasource ) ) mLayerList->setItem( j, 2, item );
{
QToolButton *btn = new QToolButton( this ); if ( QgsAuthConfigUriEdit::hasConfigId( datasource ) )
btn->setMaximumWidth( 75 ); {
btn->setMinimumHeight( 24 ); QToolButton *btn = new QToolButton( this );
btn->setText( tr( "Edit" ) ); btn->setMaximumWidth( 75 );
btn->setProperty( "row", j ); btn->setMinimumHeight( 24 );
connect( btn, &QAbstractButton::clicked, this, &QgsHandleBadLayers::editAuthCfg ); btn->setText( tr( "Edit" ) );
mLayerList->setCellWidget( j, 3, btn ); btn->setProperty( "row", j );
} connect( btn, &QAbstractButton::clicked, this, &QgsHandleBadLayers::editAuthCfg );
else mLayerList->setCellWidget( j, 3, btn );
{ }
item = new QTableWidgetItem( QString() ); else
mLayerList->setItem( j, 3, item ); {
} item = new QTableWidgetItem( QString() );
mLayerList->setItem( j, 3, item );
item = new QTableWidgetItem( datasource ); }
mLayerList->setItem( j, 4, item );
item = new QTableWidgetItem( datasource );
j++; mLayerList->setItem( j, 4, item );
}
j++;
// mLayerList->resizeColumnsToContents(); }
}
// mLayerList->resizeColumnsToContents();
void QgsHandleBadLayers::selectionChanged() }
{
void QgsHandleBadLayers::selectionChanged()
mRows.clear(); {
Q_FOREACH ( QTableWidgetItem *item, mLayerList->selectedItems() ) mRows.clear();
{
if ( item->column() != 0 ) Q_FOREACH ( QTableWidgetItem *item, mLayerList->selectedItems() )
continue; {
if ( item->column() != 0 )
bool providerFileBased = mLayerList->item( item->row(), 1 )->data( Qt::UserRole + 0 ).toBool(); continue;
if ( !providerFileBased )
continue; bool providerFileBased = mLayerList->item( item->row(), 1 )->data( Qt::UserRole + 0 ).toBool();
if ( !providerFileBased )
mRows << item->row(); continue;
}
mRows << item->row();
mBrowseButton->setEnabled( !mRows.isEmpty() ); }
}
mBrowseButton->setEnabled( !mRows.isEmpty() );
QString QgsHandleBadLayers::filename( int row ) }
{
QString type = mLayerList->item( row, 1 )->text(); QString QgsHandleBadLayers::filename( int row )
QString provider = mLayerList->item( row, 2 )->text(); {
QString datasource = mLayerList->item( row, 4 )->text(); QString type = mLayerList->item( row, 1 )->text();
QString provider = mLayerList->item( row, 2 )->text();
if ( type == QLatin1String( "vector" ) ) QString datasource = mLayerList->item( row, 4 )->text();
{
const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( provider, datasource ); if ( type == QLatin1String( "vector" ) )
// if parts is empty then provider doesn't handle this method! {
return parts.empty() ? datasource : parts.value( QStringLiteral( "path" ) ).toString(); const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( provider, datasource );
} // if parts is empty then provider doesn't handle this method!
else return parts.empty() ? datasource : parts.value( QStringLiteral( "path" ) ).toString();
{ }
return datasource; else
} {
} return datasource;
}
void QgsHandleBadLayers::setFilename( int row, const QString &filename ) }
{
if ( !QFileInfo::exists( filename ) ) void QgsHandleBadLayers::setFilename( int row, const QString &filename )
return; {
if ( !QFileInfo::exists( filename ) )
QString type = mLayerList->item( row, 1 )->text(); return;
QString provider = mLayerList->item( row, 2 )->text();
QTableWidgetItem *item = mLayerList->item( row, 4 ); QString type = mLayerList->item( row, 1 )->text();
QString provider = mLayerList->item( row, 2 )->text();
QString datasource = item->text(); QTableWidgetItem *item = mLayerList->item( row, 4 );
if ( type == QLatin1String( "vector" ) ) QString datasource = item->text();
{
if ( provider == QLatin1String( "spatialite" ) ) if ( type == QLatin1String( "vector" ) )
{ {
QgsDataSourceUri uri( datasource ); if ( provider == QLatin1String( "spatialite" ) )
uri.setDatabase( filename ); {
datasource = uri.uri(); QgsDataSourceUri uri( datasource );
} uri.setDatabase( filename );
else if ( provider == QLatin1String( "ogr" ) ) datasource = uri.uri();
{ }
QStringList theURIParts = datasource.split( '|' ); else if ( provider == QLatin1String( "ogr" ) )
theURIParts[0] = filename; {
datasource = theURIParts.join( QStringLiteral( "|" ) ); QStringList theURIParts = datasource.split( '|' );
} theURIParts[0] = filename;
else if ( provider == QLatin1String( "delimitedtext" ) ) datasource = theURIParts.join( QStringLiteral( "|" ) );
{ }
QUrl uriSource = QUrl::fromEncoded( datasource.toLatin1() ); else if ( provider == QLatin1String( "delimitedtext" ) )
QUrl uriDest = QUrl::fromLocalFile( filename ); {
uriDest.setQueryItems( uriSource.queryItems() ); QUrl uriSource = QUrl::fromEncoded( datasource.toLatin1() );
datasource = QString::fromLatin1( uriDest.toEncoded() ); QUrl uriDest = QUrl::fromLocalFile( filename );
} uriDest.setQueryItems( uriSource.queryItems() );
} datasource = QString::fromLatin1( uriDest.toEncoded() );
else }
{ }
datasource = filename; else
} {
datasource = filename;
item->setText( datasource ); }
}
item->setText( datasource );
void QgsHandleBadLayers::browseClicked() }
{
void QgsHandleBadLayers::browseClicked()
if ( mRows.size() == 1 ) {
{
int row = mRows.at( 0 ); if ( mRows.size() == 1 )
QString type = mLayerList->item( row, 1 )->text(); {
int row = mRows.at( 0 );
QString memoryQualifier, fileFilter; QString type = mLayerList->item( row, 1 )->text();
if ( type == QLatin1String( "vector" ) )
{ QString memoryQualifier, fileFilter;
memoryQualifier = QStringLiteral( "lastVectorFileFilter" ); if ( type == QLatin1String( "vector" ) )
fileFilter = mVectorFileFilter; {
} memoryQualifier = QStringLiteral( "lastVectorFileFilter" );
else fileFilter = mVectorFileFilter;
{ }
memoryQualifier = QStringLiteral( "lastRasterFileFilter" ); else
fileFilter = mRasterFileFilter; {
} memoryQualifier = QStringLiteral( "lastRasterFileFilter" );
fileFilter = mRasterFileFilter;
QString fn = filename( row ); }
if ( fn.isNull() )
return; QString fn = filename( row );
if ( fn.isNull() )
QStringList selectedFiles; return;
QString enc;
QString title = tr( "Select File to Replace '%1'" ).arg( fn ); QStringList selectedFiles;
QString enc;
QgsGuiUtils::openFilesRememberingFilter( memoryQualifier, fileFilter, selectedFiles, enc, title ); QString title = tr( "Select File to Replace '%1'" ).arg( fn );
if ( selectedFiles.size() != 1 )
{ QgsGuiUtils::openFilesRememberingFilter( memoryQualifier, fileFilter, selectedFiles, enc, title );
QMessageBox::information( this, title, tr( "Please select exactly one file." ) ); if ( selectedFiles.size() != 1 )
return; {
} QMessageBox::information( this, title, tr( "Please select exactly one file." ) );
return;
setFilename( row, selectedFiles[0] ); }
}
else if ( mRows.size() > 1 ) setFilename( row, selectedFiles[0] );
{ }
QString title = tr( "Select New Directory of Selected Files" ); else if ( mRows.size() > 1 )
{
QgsSettings settings; QString title = tr( "Select New Directory of Selected Files" );
QString lastDir = settings.value( QStringLiteral( "UI/missingDirectory" ), QDir::homePath() ).toString();
QString selectedFolder = QFileDialog::getExistingDirectory( this, title, lastDir ); QgsSettings settings;
if ( selectedFolder.isEmpty() ) QString lastDir = settings.value( QStringLiteral( "UI/missingDirectory" ), QDir::homePath() ).toString();
{ QString selectedFolder = QFileDialog::getExistingDirectory( this, title, lastDir );
return; if ( selectedFolder.isEmpty() )
} {
return;
QDir dir( selectedFolder ); }
if ( !dir.exists() )
{ QDir dir( selectedFolder );
return; if ( !dir.exists() )
} {
return;
Q_FOREACH ( int row, mRows ) }
{
bool providerFileBased = mLayerList->item( row, 1 )->data( Qt::UserRole + 0 ).toBool(); Q_FOREACH ( int row, mRows )
if ( !providerFileBased ) {
continue; bool providerFileBased = mLayerList->item( row, 1 )->data( Qt::UserRole + 0 ).toBool();
if ( !providerFileBased )
QString fn = filename( row ); continue;
if ( fn.isEmpty() )
continue; QString fn = filename( row );
if ( fn.isEmpty() )
QFileInfo fi( fn ); continue;
fi.setFile( dir, fi.fileName() );
if ( !fi.exists() ) QFileInfo fi( fn );
continue; fi.setFile( dir, fi.fileName() );
if ( !fi.exists() )
setFilename( row, fi.absoluteFilePath() ); continue;
}
} setFilename( row, fi.absoluteFilePath() );
} }
}
void QgsHandleBadLayers::editAuthCfg() }
{
QToolButton *btn = qobject_cast<QToolButton *>( sender() ); void QgsHandleBadLayers::editAuthCfg()
int row = -1; {
for ( int i = 0; i < mLayerList->rowCount(); i++ ) QToolButton *btn = qobject_cast<QToolButton *>( sender() );
{ int row = -1;
if ( mLayerList->cellWidget( i, 3 ) == btn ) for ( int i = 0; i < mLayerList->rowCount(); i++ )
{ {
row = i; if ( mLayerList->cellWidget( i, 3 ) == btn )
break; {
} row = i;
} break;
}
if ( row == -1 ) }
return;
if ( row == -1 )
QString provider = mLayerList->item( row, 2 )->text(); return;
if ( provider == QLatin1String( "none" ) )
provider.clear(); QString provider = mLayerList->item( row, 2 )->text();
if ( provider == QLatin1String( "none" ) )
QString prevuri = mLayerList->item( row, 4 )->text(); provider.clear();
QgsAuthConfigUriEdit *dlg = new QgsAuthConfigUriEdit( this, prevuri, provider ); QString prevuri = mLayerList->item( row, 4 )->text();
dlg->setWindowModality( Qt::WindowModal );
dlg->resize( 500, 500 ); QgsAuthConfigUriEdit *dlg = new QgsAuthConfigUriEdit( this, prevuri, provider );
if ( dlg->exec() ) dlg->setWindowModality( Qt::WindowModal );
{ dlg->resize( 500, 500 );
QString newuri( dlg->dataSourceUri() ); if ( dlg->exec() )
if ( newuri != prevuri ) {
{ QString newuri( dlg->dataSourceUri() );
mLayerList->item( row, 4 )->setText( newuri ); if ( newuri != prevuri )
} {
} mLayerList->item( row, 4 )->setText( newuri );
dlg->deleteLater(); }
} }
dlg->deleteLater();
void QgsHandleBadLayers::apply() }
{
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( true ); void QgsHandleBadLayers::apply()
buttonBox->button( QDialogButtonBox::Ignore )->setEnabled( false ); {
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( true );
for ( int i = 0; i < mLayerList->rowCount(); i++ ) buttonBox->button( QDialogButtonBox::Ignore )->setEnabled( false );
{ QHash<QString, QString> baseChange;
int idx = mLayerList->item( i, 0 )->data( Qt::UserRole ).toInt();
QDomNode &node = const_cast<QDomNode &>( mLayers[ idx ] ); for ( int i = 0; i < mLayerList->rowCount(); i++ )
{
QTableWidgetItem *item = mLayerList->item( i, 4 ); int idx = mLayerList->item( i, 0 )->data( Qt::UserRole ).toInt();
QString datasource = item->text(); QDomNode &node = const_cast<QDomNode &>( mLayers[ idx ] );
bool dataSourceChanged { false }; QTableWidgetItem *item = mLayerList->item( i, 4 );
const QString layerId { node.namedItem( QStringLiteral( "id" ) ).toElement().text() }; QString datasource = item->text();
const QString provider { node.namedItem( QStringLiteral( "provider" ) ).toElement().text() }; const QString basepath = datasource.left( datasource.lastIndexOf('/') )
const QString name { mLayerList->item( i, 0 )->text() }; bool changed = false;
// Try first to change the datasource of the existing layers, this will if ( mFileBase[ name ].size() == 1 )
// maintain the current status (checked/unchecked) and group {
if ( QgsProject::instance()->mapLayer( layerId ) ) if ( mFileBase[ name ][0] != basepath && !baseChange.contains( mFileBase[ name ][0] ) )
{ {
QgsDataProvider::ProviderOptions options; baseChange[ mFileBase[ name ][0] ] = basepath;
QgsMapLayer *mapLayer = QgsProject::instance()->mapLayer( layerId ); changed = true;
if ( mapLayer ) }
{ }
mapLayer->setDataSource( datasource, name, provider, options ); else if ( mFileBase[ name ].size() > 1 )
dataSourceChanged = mapLayer->isValid(); {
} if ( mFileBase[ name ].indexOf( basepath ) == -1 )
} {
const QList fileBases = mFileBase[ name ];
// If the data source was changed successfully, remove the bad layer from the dialog for ( QString fileBase : fileBases )
// otherwise, try to set the new datasource in the XML node and reload the layer, {
// finally marks with red all remaining bad layers. if ( !baseChange.contains( fileBase ) )
if ( dataSourceChanged ) {
{ baseChange[ fileBase ] = basepath;
mLayerList->removeRow( i-- ); changed = true;
} }
else }
{ }
node.namedItem( QStringLiteral( "datasource" ) ).toElement().firstChild().toText().setData( datasource ); }
if ( QgsProject::instance()->readLayer( node ) ) if ( !changed && baseChange.contains( basepath ) )
{ datasource = datasource.replace( basepath, baseChange( basepath ) );
mLayerList->removeRow( i-- );
}
else bool dataSourceChanged { false };
{ const QString layerId { node.namedItem( QStringLiteral( "id" ) ).toElement().text() };
item->setForeground( QBrush( Qt::red ) ); const QString provider { node.namedItem( QStringLiteral( "provider" ) ).toElement().text() };
} const QString name { mLayerList->item( i, 0 )->text() };
}
} // Try first to change the datasource of the existing layers, this will
// maintain the current status (checked/unchecked) and group
// Final cleanup: remove any bad layer (it should not be any btw) if ( QgsProject::instance()->mapLayer( layerId ) )
if ( mLayerList->rowCount() == 0 ) {
{ QgsDataProvider::ProviderOptions options;
QList<QgsMapLayer *> toRemove; QgsMapLayer *mapLayer = QgsProject::instance()->mapLayer( layerId );
const auto mapLayers = QgsProject::instance()->mapLayers(); if ( mapLayer )
for ( const auto &l : mapLayers ) {
{ mapLayer->setDataSource( datasource, name, provider, options );
if ( ! l->isValid() ) dataSourceChanged = mapLayer->isValid();
toRemove << l; }
} }
QgsProject::instance()->removeMapLayers( toRemove );
accept(); // If the data source was changed successfully, remove the bad layer from the dialog
} // otherwise, try to set the new datasource in the XML node and reload the layer,
// finally marks with red all remaining bad layers.
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( false ); if ( dataSourceChanged )
{
} mLayerList->removeRow( i-- );
}
void QgsHandleBadLayers::accept() else
{ {
node.namedItem( QStringLiteral( "datasource" ) ).toElement().firstChild().toText().setData( datasource );
if ( mLayerList->rowCount() > 0 && if ( QgsProject::instance()->readLayer( node ) )
QMessageBox::warning( this, {
tr( "Unhandled layer will be lost." ), mLayerList->removeRow( i-- );
tr( "There are still %n unhandled layer(s). If they are not fixed, they will be disabled/deactivated until the project is opened again.", }
"unhandled layers", else
mLayerList->rowCount() ), {
QMessageBox::Ok | QMessageBox::Cancel, item->setForeground( QBrush( Qt::red ) );
QMessageBox::Cancel ) == QMessageBox::Cancel ) }
{ }
return; }
}
QList<QgsMapLayer *> toRemove; // Final cleanup: remove any bad layer (it should not be any btw)
for ( const auto &l : QgsProject::instance()->mapLayers( ) ) if ( mLayerList->rowCount() == 0 )
{ {
if ( ! l->isValid() ) QList<QgsMapLayer *> toRemove;
toRemove << l; const auto mapLayers = QgsProject::instance()->mapLayers();
} for ( const auto &l : mapLayers )
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( true ); {
QgsProject::instance()->removeMapLayers( toRemove ); if ( ! l->isValid() )
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( false ); toRemove << l;
mLayerList->clear(); }
QgsProject::instance()->removeMapLayers( toRemove );
QDialog::accept(); accept();
} }
int QgsHandleBadLayers::layerCount() QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( false );
{
return mLayerList->rowCount(); }
}
void QgsHandleBadLayers::accept()
{
if ( mLayerList->rowCount() > 0 &&
QMessageBox::warning( this,
tr( "Unhandled layer will be lost." ),
tr( "There are still %n unhandled layer(s). If they are not fixed, they will be disabled/deactivated until the project is opened again.",
"unhandled layers",
mLayerList->rowCount() ),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Cancel ) == QMessageBox::Cancel )
{
return;
}
QList<QgsMapLayer *> toRemove;
for ( const auto &l : QgsProject::instance()->mapLayers( ) )
{
if ( ! l->isValid() )
toRemove << l;
}
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( true );
QgsProject::instance()->removeMapLayers( toRemove );
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( false );
mLayerList->clear();
QDialog::accept();
}
int QgsHandleBadLayers::layerCount()
{
return mLayerList->rowCount();
}

View File

@ -1,79 +1,80 @@
/*************************************************************************** /***************************************************************************
qgshandlebadlayers.h - description qgshandlebadlayers.h - description
------------------- -------------------
begin : Sat 05 Mar 2011 begin : Sat 05 Mar 2011
copyright : (C) 2011 by Juergen E. Fischer, norBIT GmbH copyright : (C) 2011 by Juergen E. Fischer, norBIT GmbH
email : jef at norbit dot de email : jef at norbit dot de
***************************************************************************/ ***************************************************************************/
/*************************************************************************** /***************************************************************************
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
***************************************************************************/ ***************************************************************************/
#ifndef QGSHANDLEBADLAYERS_H #ifndef QGSHANDLEBADLAYERS_H
#define QGSHANDLEBADLAYERS_H #define QGSHANDLEBADLAYERS_H
#include "ui_qgshandlebadlayersbase.h" #include "ui_qgshandlebadlayersbase.h"
#include "qgsprojectbadlayerhandler.h" #include "qgsprojectbadlayerhandler.h"
#include "qgis_app.h" #include "qgis_app.h"
class APP_EXPORT QgsHandleBadLayersHandler class APP_EXPORT QgsHandleBadLayersHandler
: public QObject : public QObject
, public QgsProjectBadLayerHandler , public QgsProjectBadLayerHandler
{ {
Q_OBJECT Q_OBJECT
public: public:
QgsHandleBadLayersHandler() = default; QgsHandleBadLayersHandler() = default;
//! Implementation of the handler //! Implementation of the handler
void handleBadLayers( const QList<QDomNode> &layers ) override; void handleBadLayers( const QList<QDomNode> &layers ) override;
signals: signals:
/** /**
* Emitted when layers have changed * Emitted when layers have changed
* \since QGIS 3.6 * \since QGIS 3.6
*/ */
void layersChanged(); void layersChanged();
}; };
class QPushButton; class QPushButton;
class APP_EXPORT QgsHandleBadLayers class APP_EXPORT QgsHandleBadLayers
: public QDialog : public QDialog
, public Ui::QgsHandleBadLayersBase , public Ui::QgsHandleBadLayersBase
{ {
Q_OBJECT Q_OBJECT
public: public:
QgsHandleBadLayers( const QList<QDomNode> &layers ); QgsHandleBadLayers( const QList<QDomNode> &layers );
int layerCount(); int layerCount();
private slots: private slots:
void selectionChanged(); void selectionChanged();
void browseClicked(); void browseClicked();
void editAuthCfg(); void editAuthCfg();
void apply(); void apply();
void accept() override; void accept() override;
private: private:
QPushButton *mBrowseButton = nullptr; QPushButton *mBrowseButton = nullptr;
QPushButton *mApplyButton = nullptr; QPushButton *mApplyButton = nullptr;
const QList<QDomNode> &mLayers; const QList<QDomNode> &mLayers;
QList<int> mRows; QList<int> mRows;
QString mVectorFileFilter; QString mVectorFileFilter;
QString mRasterFileFilter; QString mRasterFileFilter;
QHash <QString, QList<QString> > mFileBase;
QString filename( int row );
void setFilename( int row, const QString &filename ); QString filename( int row );
}; void setFilename( int row, const QString &filename );
};
#endif
#endif