Skip to content

Commit

Permalink
Merge pull request #4064 from jgrocha/delete-style-from-db-provider-p…
Browse files Browse the repository at this point in the history
…ostgis

Delete style from db provider postgis
  • Loading branch information
nyalldawson committed Feb 5, 2017
2 parents 6ca2cc1 + 20eea32 commit 4f7d9cd
Show file tree
Hide file tree
Showing 13 changed files with 293 additions and 34 deletions.
8 changes: 8 additions & 0 deletions python/core/qgsvectordataprovider.sip
Expand Up @@ -407,6 +407,14 @@ class QgsVectorDataProvider : QgsDataProvider
*/
virtual bool isSaveAndLoadStyleToDBSupported() const;

/**
* Checks if the provider supports style removal
* Must be implemented by providers that support delete styles from db returning true
* @note added in QGIS 3.0
* @return true if delete operation is supported by the provider
*/
virtual bool isDeleteStyleFromDbSupported() const;

static QVariant convertValue( QVariant::Type type, const QString& value );

/**
Expand Down
9 changes: 9 additions & 0 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -649,6 +649,15 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
*/
virtual QString getStyleFromDatabase( const QString& styleId, QString &msgError /Out/ );

/**
* Delete a style from the database
* @note added in QGIS 3.0
* @param styleId the provider's layer_styles table id of the style to delete
* @param msgError reference to string that will be updated with any error messages
* @return true in case of success
*/
virtual bool deleteStyleFromDatabase( const QString& styleId, QString &msgError /Out/ );

/**
* Load a named style from file/local db/datasource db
* @param theURI the URI of the style or the URI of the layer
Expand Down
120 changes: 104 additions & 16 deletions src/app/qgsloadstylefromdbdialog.cpp
Expand Up @@ -15,6 +15,7 @@

#include "qgsloadstylefromdbdialog.h"
#include "qgslogger.h"
#include "qgisapp.h"

#include <QSettings>
#include <QMessageBox>
Expand All @@ -25,10 +26,10 @@ QgsLoadStyleFromDBDialog::QgsLoadStyleFromDBDialog( QWidget *parent )
, mSectionLimit( 0 )
{
setupUi( this );
setWindowTitle( QStringLiteral( "Load style from database" ) );
mSelectedStyleId = QLatin1String( "" );
setWindowTitle( QStringLiteral( "Database styles manager" ) );

mLoadButton->setDisabled( true );
mDeleteButton->setDisabled( true );
mRelatedTable->setEditTriggers( QTableWidget::NoEditTriggers );
mRelatedTable->horizontalHeader()->setStretchLastSection( true );
mRelatedTable->setSelectionBehavior( QTableWidget::SelectRows );
Expand All @@ -39,20 +40,21 @@ QgsLoadStyleFromDBDialog::QgsLoadStyleFromDBDialog( QWidget *parent )
mOthersTable->setSelectionBehavior( QTableWidget::SelectRows );
mOthersTable->verticalHeader()->setVisible( false );

connect( mRelatedTable, SIGNAL( cellClicked( int, int ) ), this, SLOT( cellSelectedRelatedTable( int ) ) );
connect( mOthersTable, SIGNAL( cellClicked( int, int ) ), this, SLOT( cellSelectedOthersTable( int ) ) );
connect( mRelatedTable, SIGNAL( doubleClicked( QModelIndex ) ), this, SLOT( accept() ) );
connect( mOthersTable, SIGNAL( doubleClicked( QModelIndex ) ), this, SLOT( accept() ) );
connect( mCancelButton, SIGNAL( clicked() ), this, SLOT( reject() ) );
connect( mLoadButton, SIGNAL( clicked() ), this, SLOT( accept() ) );
connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLoadStyleFromDBDialog::onRelatedTableSelectionChanged );
connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLoadStyleFromDBDialog::onOthersTableSelectionChanged );
connect( mRelatedTable, &QTableWidget::doubleClicked, this, &QDialog::accept );
connect( mOthersTable, &QTableWidget::doubleClicked, this, &QDialog::accept );
connect( mCancelButton, &QPushButton::clicked, this, &QDialog::reject );
connect( mLoadButton, &QPushButton::clicked, this, &QDialog::accept );
connect( mDeleteButton, &QPushButton::clicked, this, &QgsLoadStyleFromDBDialog::deleteStyleFromDB );

setTabOrder( mRelatedTable, mOthersTable );
setTabOrder( mOthersTable, mCancelButton );
setTabOrder( mCancelButton, mLoadButton );
setTabOrder( mCancelButton, mDeleteButton );
setTabOrder( mDeleteButton, mLoadButton );

QSettings settings;
restoreGeometry( settings.value( QStringLiteral( "/Windows/loadStyleFromDb/geometry" ) ).toByteArray() );

}

QgsLoadStyleFromDBDialog::~QgsLoadStyleFromDBDialog()
Expand Down Expand Up @@ -102,14 +104,100 @@ QString QgsLoadStyleFromDBDialog::getSelectedStyleId()
return mSelectedStyleId;
}

void QgsLoadStyleFromDBDialog::cellSelectedRelatedTable( int r )
void QgsLoadStyleFromDBDialog::setLayer( QgsVectorLayer *l )
{
mLoadButton->setEnabled( true );
mSelectedStyleId = mRelatedTable->item( r, 0 )->data( Qt::UserRole ).toString();
mLayer = l;
mDeleteButton->setVisible( mLayer->dataProvider()->isDeleteStyleFromDbSupported() );
}

void QgsLoadStyleFromDBDialog::cellSelectedOthersTable( int r )
void QgsLoadStyleFromDBDialog::onRelatedTableSelectionChanged()
{
mLoadButton->setEnabled( true );
mSelectedStyleId = mOthersTable->item( r, 0 )->data( Qt::UserRole ).toString();
selectionChanged( mRelatedTable );
if ( mRelatedTable->selectionModel()->hasSelection() )
{
if ( mOthersTable->selectionModel()->hasSelection() )
{
disconnect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLoadStyleFromDBDialog::onOthersTableSelectionChanged );
QTableWidgetSelectionRange range( 0, 0, mOthersTable->rowCount() - 1, mOthersTable->columnCount() - 1 );
mOthersTable->setRangeSelected( range, false );
connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLoadStyleFromDBDialog::onOthersTableSelectionChanged );
}
}
}

void QgsLoadStyleFromDBDialog::onOthersTableSelectionChanged()
{
selectionChanged( mOthersTable );
if ( mOthersTable->selectionModel()->hasSelection() )
{
if ( mRelatedTable->selectionModel()->hasSelection() )
{
disconnect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLoadStyleFromDBDialog::onRelatedTableSelectionChanged );
QTableWidgetSelectionRange range( 0, 0, mRelatedTable->rowCount() - 1, mRelatedTable->columnCount() - 1 );
mRelatedTable->setRangeSelected( range, false );
connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLoadStyleFromDBDialog::onRelatedTableSelectionChanged );
}
}
}

void QgsLoadStyleFromDBDialog::selectionChanged( QTableWidget *styleTable )
{
QTableWidgetItem *item;
QList<QTableWidgetItem *> selected = styleTable->selectedItems();

if ( !selected.isEmpty() )
{
item = selected.at( 0 );
mSelectedStyleName = item->text();
mSelectedStyleId = item->data( Qt::UserRole ).toString();
mLoadButton->setEnabled( true );
mDeleteButton->setEnabled( true );
}
else
{
mSelectedStyleName.clear();
mSelectedStyleId.clear();
mLoadButton->setEnabled( false );
mDeleteButton->setEnabled( false );
}
}

void QgsLoadStyleFromDBDialog::deleteStyleFromDB()
{
QString msgError;
QString opInfo = QObject::tr( "Delete style %1 from %2" ).arg( mSelectedStyleName, mLayer->providerType() );

if ( QMessageBox::question( nullptr, QObject::tr( "Delete style" ),
QObject::tr( "Are you sure you want to delete the style %1?" ).arg( mSelectedStyleName ),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
return;

mLayer->deleteStyleFromDatabase( mSelectedStyleId, msgError );
if ( !msgError.isNull() )
{
QgsDebugMsg( opInfo + " failed." );
QgisApp::instance()->messageBar()->pushMessage( opInfo , tr( "%1: fail. %2" ).arg( opInfo, msgError ), QgsMessageBar::WARNING, QgisApp::instance()->messageTimeout() );
}
else
{
QgisApp::instance()->messageBar()->pushMessage( opInfo , tr( "%1: success" ).arg( opInfo ), QgsMessageBar::INFO, QgisApp::instance()->messageTimeout() );

//Delete all rows from the UI table widgets
mRelatedTable->setRowCount( 0 );
mOthersTable->setRowCount( 0 );

//Fill UI widgets again from DB. Other users might have change the styles meanwhile.
QString errorMsg;
QStringList ids, names, descriptions;
//get the list of styles in the db
int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
if ( !errorMsg.isNull() )
{
QgisApp::instance()->messageBar()->pushMessage( tr( "Error occurred retrieving styles from database" ), errorMsg, QgsMessageBar::WARNING, QgisApp::instance()->messageTimeout() );
}
else
{
initializeLists( ids, names, descriptions, sectionLimit );
}
}
}
12 changes: 9 additions & 3 deletions src/app/qgsloadstylefromdbdialog.h
Expand Up @@ -19,12 +19,14 @@
#include "ui_qgsloadstylefromdbdialog.h"
#include "qgisgui.h"
#include "qgis_app.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"

class APP_EXPORT QgsLoadStyleFromDBDialog : public QDialog, private Ui::QgsLoadStyleFromDBDialogLayout
{
QString mSelectedStyleId;
QString mSelectedStyleName;
int mSectionLimit;
QString qmlStyle;
Q_OBJECT
public:
explicit QgsLoadStyleFromDBDialog( QWidget *parent = nullptr );
Expand All @@ -33,12 +35,16 @@ class APP_EXPORT QgsLoadStyleFromDBDialog : public QDialog, private Ui::QgsLoadS

void initializeLists( const QStringList& ids, const QStringList& names, const QStringList& descriptions, int sectionLimit );
QString getSelectedStyleId();
void selectionChanged( QTableWidget *styleTable );
void setLayer( QgsVectorLayer *l );

public slots:
void cellSelectedRelatedTable( int r );
void cellSelectedOthersTable( int r );
void onRelatedTableSelectionChanged();
void onOthersTableSelectionChanged();
void deleteStyleFromDB();

private:
QgsVectorLayer *mLayer = nullptr;

};

Expand Down
7 changes: 4 additions & 3 deletions src/app/qgsvectorlayerproperties.cpp
Expand Up @@ -163,7 +163,7 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
//for loading
mLoadStyleMenu = new QMenu( this );
mLoadStyleMenu->addAction( tr( "Load from file..." ) );
mLoadStyleMenu->addAction( tr( "Load from database" ) );
mLoadStyleMenu->addAction( tr( "Database styles manager" ) );
//mActionLoadStyle->setContextMenuPolicy( Qt::PreventContextMenu );
mActionLoadStyle->setMenu( mLoadStyleMenu );

Expand Down Expand Up @@ -883,11 +883,11 @@ void QgsVectorLayerProperties::saveStyleAs( StyleType styleType )

if ( !msgError.isNull() )
{
QMessageBox::warning( this, infoWindowTitle, msgError );
QgisApp::instance()->messageBar()->pushMessage( infoWindowTitle , msgError, QgsMessageBar::WARNING, QgisApp::instance()->messageTimeout() );
}
else
{
QMessageBox::information( this, infoWindowTitle, tr( "Style saved" ) );
QgisApp::instance()->messageBar()->pushMessage( infoWindowTitle , tr( "Style saved" ), QgsMessageBar::INFO, QgisApp::instance()->messageTimeout() );
}

}
Expand Down Expand Up @@ -1022,6 +1022,7 @@ void QgsVectorLayerProperties::showListOfStylesFromDatabase()
}

QgsLoadStyleFromDBDialog dialog;
dialog.setLayer( mLayer );
dialog.initializeLists( ids, names, descriptions, sectionLimit );

if ( dialog.exec() == QDialog::Accepted )
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsvectordataprovider.cpp
Expand Up @@ -695,6 +695,11 @@ bool QgsVectorDataProvider::isSaveAndLoadStyleToDBSupported() const
return false;
}

bool QgsVectorDataProvider::isDeleteStyleFromDbSupported() const
{
return false;
}

void QgsVectorDataProvider::pushError( const QString& msg ) const
{
QgsDebugMsg( msg );
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsvectordataprovider.h
Expand Up @@ -470,6 +470,12 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
*/
virtual bool isSaveAndLoadStyleToDBSupported() const;

/**
* It returns false by default.
* Must be implemented by providers that support delete styles from db returning true
*/
virtual bool isDeleteStyleFromDbSupported() const;

static QVariant convertValue( QVariant::Type type, const QString& value );

/**
Expand Down
38 changes: 27 additions & 11 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -119,6 +119,12 @@ typedef QString getStyleById_t(
QString& errCause
);

typedef bool deleteStyleById_t(
const QString& uri,
QString styleID,
QString& errCause
);

QgsVectorLayer::QgsVectorLayer( const QString& vectorLayerPath,
const QString& baseName,
const QString& providerKey,
Expand Down Expand Up @@ -4266,8 +4272,7 @@ QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const

int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
{
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
QLibrary *myLib = pReg->providerLibrary( mProviderKey );
QScopedPointer<QLibrary> myLib( QgsProviderRegistry::instance()->providerLibrary( mProviderKey ) );
if ( !myLib )
{
msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
Expand All @@ -4277,7 +4282,6 @@ int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names,

if ( !listStylesExternalMethod )
{
delete myLib;
msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey, QStringLiteral( "listStyles" ) );
return -1;
}
Expand All @@ -4287,8 +4291,7 @@ int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names,

QString QgsVectorLayer::getStyleFromDatabase( const QString& styleId, QString &msgError )
{
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
QLibrary *myLib = pReg->providerLibrary( mProviderKey );
QScopedPointer<QLibrary> myLib( QgsProviderRegistry::instance()->providerLibrary( mProviderKey ) );
if ( !myLib )
{
msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
Expand All @@ -4298,22 +4301,37 @@ QString QgsVectorLayer::getStyleFromDatabase( const QString& styleId, QString &m

if ( !getStyleByIdMethod )
{
delete myLib;
msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey, QStringLiteral( "getStyleById" ) );
return QString();
}

return getStyleByIdMethod( mDataSource, styleId, msgError );
}

bool QgsVectorLayer::deleteStyleFromDatabase( const QString& styleId, QString &msgError )
{
QScopedPointer<QLibrary> myLib( QgsProviderRegistry::instance()->providerLibrary( mProviderKey ) );
if ( !myLib )
{
msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
return false;
}
deleteStyleById_t* deleteStyleByIdMethod = reinterpret_cast< deleteStyleById_t * >( cast_to_fptr( myLib->resolve( "deleteStyleById" ) ) );
if ( !deleteStyleByIdMethod )
{
msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey, QStringLiteral( "deleteStyleById" ) );
return false;
}
return deleteStyleByIdMethod( mDataSource, styleId, msgError );
}


void QgsVectorLayer::saveStyleToDatabase( const QString& name, const QString& description,
bool useAsDefault, const QString& uiFileContent, QString &msgError )
{

QString sldStyle, qmlStyle;
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
QLibrary *myLib = pReg->providerLibrary( mProviderKey );
QScopedPointer<QLibrary> myLib( QgsProviderRegistry::instance()->providerLibrary( mProviderKey ) );
if ( !myLib )
{
msgError = QObject::tr( "Unable to load %1 provider" ).arg( mProviderKey );
Expand All @@ -4323,7 +4341,6 @@ void QgsVectorLayer::saveStyleToDatabase( const QString& name, const QString& de

if ( !saveStyleExternalMethod )
{
delete myLib;
msgError = QObject::tr( "Provider %1 has no %2 method" ).arg( mProviderKey, QStringLiteral( "saveStyle" ) );
return;
}
Expand Down Expand Up @@ -4359,8 +4376,7 @@ QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &theResultFl
QgsDataSourceUri dsUri( theURI );
if ( !loadFromLocalDB && mDataProvider && mDataProvider->isSaveAndLoadStyleToDBSupported() )
{
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
QLibrary *myLib = pReg->providerLibrary( mProviderKey );
QScopedPointer<QLibrary> myLib( QgsProviderRegistry::instance()->providerLibrary( mProviderKey ) );
if ( myLib )
{
loadStyle_t* loadStyleExternalMethod = reinterpret_cast< loadStyle_t * >( cast_to_fptr( myLib->resolve( "loadStyle" ) ) );
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsvectorlayer.h
Expand Up @@ -732,6 +732,15 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
virtual QString getStyleFromDatabase( const QString& styleId, QString &msgError );

/**
* Delete a style from the database
* @note added in QGIS 3.0
* @param styleId the provider's layer_styles table id of the style to delete
* @param msgError reference to string that will be updated with any error messages
* @return true in case of success
*/
virtual bool deleteStyleFromDatabase( const QString& styleId, QString &msgError );

/**
* Load a named style from file/local db/datasource db
* @param theURI the URI of the style or the URI of the layer
Expand Down

0 comments on commit 4f7d9cd

Please sign in to comment.