Skip to content

Commit

Permalink
Move change data source action to app
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed Nov 5, 2018
1 parent 8d9d52d commit fd40042
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 107 deletions.
63 changes: 62 additions & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -101,6 +101,7 @@

#include "qgsgui.h"
#include "qgsnative.h"
#include "qgsdatasourceselectdialog.h"

#ifdef HAVE_OPENCL
#include "qgsopenclutils.h"
Expand Down Expand Up @@ -3943,7 +3944,8 @@ void QgisApp::initLayerTreeView()
new QgsLayerTreeViewFilterIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
new QgsLayerTreeViewEmbeddedIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
new QgsLayerTreeViewMemoryIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
new QgsLayerTreeViewBadLayerIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
QgsLayerTreeViewBadLayerIndicatorProvider *badLayerIndicatorProvider = new QgsLayerTreeViewBadLayerIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
connect( badLayerIndicatorProvider, &QgsLayerTreeViewBadLayerIndicatorProvider::requestChangeDataSource, this, &QgisApp::changeDataSource );
new QgsLayerTreeViewNonRemovableIndicatorProvider( mLayerTreeView ); // gets parented to the layer view

setupLayerTreeViewFromSettings();
Expand Down Expand Up @@ -3996,6 +3998,9 @@ void QgisApp::initLayerTreeView()
actionCollapseAll->setToolTip( tr( "Collapse All" ) );
connect( actionCollapseAll, &QAction::triggered, mLayerTreeView, &QgsLayerTreeView::collapseAllNodes );

// Change data source action
connect( mLayerTreeView, &QgsLayerTreeView::requestChangeDataSource, this, &QgisApp::changeDataSource );

QToolBar *toolbar = new QToolBar();
toolbar->setIconSize( iconSize( true ) );
toolbar->addAction( mActionStyleDock );
Expand Down Expand Up @@ -6937,6 +6942,62 @@ void QgisApp::refreshFeatureActions()
updateDefaultFeatureAction( mFeatureActionMenu->activeAction() );
}

void QgisApp::changeDataSource( QgsMapLayer *layer )
{
// Get provider type
QString providerType( layer->providerType() );
QgsMapLayer::LayerType layerType( layer->type() );

QgsDataSourceSelectDialog dlg( true, layerType );

if ( dlg.exec() == QDialog::Accepted )
{
QgsMimeDataUtils::Uri uri( dlg.uri() );
if ( uri.isValid() )
{
bool layerIsValid( layer->isValid() );
layer->setDataSource( uri.uri, layer->name(), uri.providerKey, QgsDataProvider::ProviderOptions() );
// Re-apply style
if ( !( layerIsValid && layer->originalXmlProperties().isEmpty() ) )
{
QgsReadWriteContext context;
context.setPathResolver( QgsProject::instance()->pathResolver() );
context.setProjectTranslator( QgsProject::instance() );
QString errorMsg;
QDomDocument doc;
if ( doc.setContent( layer->originalXmlProperties() ) )
{
QDomNode layer_node( doc.firstChild( ) );
if ( ! layer->readSymbology( layer_node, errorMsg, context ) )
{
QgsDebugMsg( QStringLiteral( "Failed to restore original layer style from stored XML for layer %1: %2" )
.arg( layer->name( ) )
.arg( errorMsg ) );
}
}
else
{
QgsDebugMsg( QStringLiteral( "Failed to create XML QDomDocument for layer %1: %2" )
.arg( layer->name( ) )
.arg( errorMsg ) );
}
}

// All the following code is necessary to refresh the layer
QgsLayerTreeModel *model = qobject_cast<QgsLayerTreeModel *>( mLayerTreeView->model() );
if ( model )
{
QgsLayerTreeLayer *tl( model->rootGroup()->findLayer( layer->id() ) );
if ( tl && tl->itemVisibilityChecked() )
{
tl->setItemVisibilityChecked( false );
tl->setItemVisibilityChecked( true );
}
}
}
}
}

void QgisApp::measure()
{
mMapCanvas->setMapTool( mMapTools.mMeasureDist );
Expand Down
16 changes: 13 additions & 3 deletions src/app/qgisapp.h
Expand Up @@ -907,6 +907,16 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
*/
QgsBrowserModel *browserModel();

/*
* Change data source for \a layer, a data source selection dialog
* will be opened and if accepted the data selected source will be
* applied.
*
* In case the layer was originally invalid and it had the original
* XML layer properties, the properties will be applied.
*/
void changeDataSource( QgsMapLayer *layer );

/**
* Add a raster layer directly without prompting user for location
The caller must provide information compatible with the provider plugin
Expand Down Expand Up @@ -936,9 +946,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
/**
* \brief overloaded version of the private addLayer method that takes a list of
* file names instead of prompting user with a dialog.
\param enc encoding type for the layer
\param dataSourceType type of ogr datasource
\returns true if successfully added layer
* \param enc encoding type for the layer
* \param dataSourceType type of ogr datasource
* \returns true if successfully added layer
*/
bool addVectorLayers( const QStringList &layerQStringList, const QString &enc, const QString &dataSourceType );

Expand Down
16 changes: 13 additions & 3 deletions src/app/qgsapplayertreeviewmenuprovider.cpp
Expand Up @@ -138,8 +138,6 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>( layer );
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );

// TODO: check if it is not valid and offer set data source

if ( layer && layer->isSpatial() )
{
menu->addAction( actions->actionZoomToLayer( mCanvas, menu ) );
Expand Down Expand Up @@ -201,6 +199,18 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()

menu->addSeparator();

// change data source is only supported for vectors and rasters
if ( vlayer || rlayer )
{

QAction *a = new QAction( tr( "Change data source" ), menu );
connect( a, &QAction::triggered, [ & ]
{
QgisApp::instance()->changeDataSource( layer );
} );
menu->addAction( a );
}

if ( vlayer )
{
QAction *toggleEditingAction = QgisApp::instance()->actionToggleEditing();
Expand All @@ -212,7 +222,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
QgisApp::instance(), SLOT( attributeTable() ) );

// allow editing
int cap = vlayer->dataProvider()->capabilities();
unsigned int cap = vlayer->dataProvider()->capabilities();
if ( cap & QgsVectorDataProvider::EditingCapabilities )
{
if ( toggleEditingAction )
Expand Down
103 changes: 3 additions & 100 deletions src/app/qgslayertreeviewbadlayerindicator.cpp
Expand Up @@ -42,109 +42,12 @@ void QgsLayerTreeViewBadLayerIndicatorProvider::onIndicatorClicked( const QModel
if ( !QgsLayerTree::isLayer( node ) )
return;

// Only raster/vector for now are supported
QgsMapLayer *layer = nullptr;
if ( qobject_cast<QgsVectorLayer *>( QgsLayerTree::toLayer( node )->layer() ) ||
qobject_cast<QgsRasterLayer *>( QgsLayerTree::toLayer( node )->layer() ) )
{
layer = qobject_cast<QgsMapLayer *>( QgsLayerTree::toLayer( node )->layer() );
}
QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( QgsLayerTree::toLayer( node )->layer() );

if ( !layer )
return;

// Get provider type
QString providerType( layer->providerType() );
QgsMapLayer::LayerType layerType( layer->type() );


// Builds the dialog to select a new data source
QgsBrowserModel browserModel;
browserModel.initialize();
QgsBrowserProxyModel proxyModel;
proxyModel.setBrowserModel( &browserModel );
proxyModel.setFilterByLayerType( true );
proxyModel.setLayerType( layerType );
QDialog dlg;
dlg.setWindowTitle( tr( "Select the new data source" ) );
QByteArray dlgGeom( QgsSettings().value( QStringLiteral( "/Windows/selectDataSourceDialog/geometry" ), QVariant(), QgsSettings::Section::App ).toByteArray() );
dlg.restoreGeometry( dlgGeom );
QVBoxLayout lay( &dlg );
QgsBrowserTreeView *browserWidget( new QgsBrowserTreeView( ) );
browserWidget->setModel( &proxyModel );
browserWidget->setHeaderHidden( true );
lay.addWidget( browserWidget );
QDialogButtonBox *buttonBox( new QDialogButtonBox( QDialogButtonBox::StandardButton::Ok | QDialogButtonBox::StandardButton::Cancel ) );
lay.addWidget( buttonBox );
connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false );

std::function<bool( const QModelIndex & )> isItemCompatible = [ & ]( const QModelIndex & index )
{
if ( index.isValid() )
{
const QgsLayerItem *item = qobject_cast<QgsLayerItem *>( proxyModel.dataItem( index ) );
if ( item && item->mapLayerType() == layerType )
{
return true;
}
}
return false;
};

connect( browserWidget, &QgsBrowserTreeView::clicked, [ & ]( const QModelIndex & index )
{
buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isItemCompatible( index ) );
} );

dlg.setLayout( &lay );
if ( dlg.exec() == QDialog::Accepted )
{
QModelIndex idx = browserWidget->currentIndex();
if ( isItemCompatible( idx ) )
{
const QgsDataItem *item( proxyModel.dataItem( idx ) );
layer->setDataSource( item->mimeUri().uri, layer->name(), item->mimeUri().providerKey, QgsDataProvider::ProviderOptions() );
// Re-apply style
if ( ! layer->originalXmlProperties().isEmpty() )
{
QgsReadWriteContext context;
context.setPathResolver( QgsProject::instance()->pathResolver() );
context.setProjectTranslator( QgsProject::instance() );
QString errorMsg;
QDomDocument doc;
if ( doc.setContent( layer->originalXmlProperties() ) )
{
QDomNode layer_node( doc.firstChild( ) );
if ( ! layer->readSymbology( layer_node, errorMsg, context ) )
{
QgsDebugMsg( QStringLiteral( "Failed to restore original layer style from stored XML for layer %1: %2" )
.arg( layer->name( ) )
.arg( errorMsg ) );
}
}
else
{
QgsDebugMsg( QStringLiteral( "Failed to create XML QDomDocument for layer %1: %2" )
.arg( layer->name( ) )
.arg( errorMsg ) );
}
}

// All the following code is necessary to refresh the layer
QgsLayerTreeModel *model = qobject_cast<QgsLayerTreeModel *>( mLayerTreeView->model() );
if ( model )
{
QgsLayerTreeLayer *tl( model->rootGroup()->findLayer( layer->id() ) );
if ( tl && tl->itemVisibilityChecked() )
{
tl->setItemVisibilityChecked( false );
tl->setItemVisibilityChecked( true );
}
}
}
}
QgsSettings().setValue( QStringLiteral( "/Windows/selectDataSourceDialog/geometry" ), dlg.saveGeometry(), QgsSettings::Section::App );
emit requestChangeDataSource( layer );
}

QString QgsLayerTreeViewBadLayerIndicatorProvider::iconName( QgsMapLayer *layer )
Expand Down
9 changes: 9 additions & 0 deletions src/app/qgslayertreeviewbadlayerindicator.h
Expand Up @@ -29,9 +29,18 @@ class QgsLayerTreeViewBadLayerIndicatorProvider : public QgsLayerTreeViewIndicat
public:
explicit QgsLayerTreeViewBadLayerIndicatorProvider( QgsLayerTreeView *view );

signals:

/**
* This signal is emitted when the user clicks on the bad layer indicator icon
* \param maplayer for change data source request
*/
void requestChangeDataSource( QgsMapLayer *maplayer );

protected slots:
void onIndicatorClicked( const QModelIndex &index ) override;


private:
QString iconName( QgsMapLayer *layer ) override;
QString tooltipText( QgsMapLayer *layer ) override;
Expand Down

0 comments on commit fd40042

Please sign in to comment.