-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Delete style from db provider postgis #4064
Delete style from db provider postgis #4064
Conversation
I'm still learning how to contribute. I would really appreciate if someone can guide me to solve the two issues reported by Travis, regarding documentation and sip coverage. documentation
Where and how to document these two new methods? sip coverage
Where do I add these two new methods? local testsOn my local qgis sources, I can run almost all tests. But |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didnt' test the PR, but generally speacking, I'm in favour of this PR.
src/app/qgsloadstylefromdbdialog.cpp
Outdated
@@ -25,10 +25,12 @@ QgsLoadStyleFromDBDialog::QgsLoadStyleFromDBDialog( QWidget *parent ) | |||
, mSectionLimit( 0 ) | |||
{ | |||
setupUi( this ); | |||
setWindowTitle( QStringLiteral( "Load style from database" ) ); | |||
setWindowTitle( QStringLiteral( "Saved styles manager" ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like, but would be necessary to leave reference to DB saved styles, otherwise can be confusing if style is saved on file system.
options can be:
- DB Saved styles manager
- Manage DB save styles
- DB Saved styles
- ony other
src/app/qgsloadstylefromdbdialog.cpp
Outdated
|
||
if ( !msgError.isNull() ) | ||
{ | ||
QMessageBox::warning( this, infoWindowTitle, msgError ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be better use QgsMessageBar instead of dialog boxes
src/app/qgsloadstylefromdbdialog.cpp
Outdated
} | ||
else | ||
{ | ||
QMessageBox::information( this, infoWindowTitle, tr( "Style deleted" ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as above: QgsMessageBar expecially for notification messages
src/app/qgsloadstylefromdbdialog.cpp
Outdated
int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg ); | ||
if ( !errorMsg.isNull() ) | ||
{ | ||
QMessageBox::warning( this, tr( "Error occurred retrieving styles from database" ), errorMsg ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as above
src/app/qgsvectorlayerproperties.cpp
Outdated
@@ -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( "Saved styles manager" ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as first message... lack of reference to DB
check https://dash.orfeo-toolbox.org/viewBuildError.php?type=1&buildid=259255 about Q_UNUSED build warning and more |
"Saved styles manager" renamed to "Database styles manager"
@luipir Thanks for your feedback. It was really helpful. This is just a small contribution to solve the current QGIS limitation, regarding style removal from the provider. I would like to have a much more improved panel to handle the styles from the DB, supporting load, save, delete, rename, clone, preview, change the default style for the layer, etc. I'm working on this. I'll discuss it soon as I get something to show. |
in this PR, that is a new functionality, there is a lack of tests. In travis (AFAIK) there is a server to test against, but I can't find a test template to inspire writing a test. |
Travis pg db is here: a compex example how to setup and use a pg db during test is here it make sense to have a setup sql to create db and to test against |
@luipir I've checked out related tests. There is already one provider with tests related to saved styles by @rouault I've followed @rouault approach and I added a new |
python/core/qgsvectorlayer.sip
Outdated
@@ -685,6 +685,11 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator | |||
virtual QString getStyleFromDatabase( const QString& styleId, QString &msgError /Out/ ); | |||
|
|||
/** | |||
* Will delete the named style corresponding to style id provided from the database | |||
*/ | |||
virtual void deleteStyleFromDatabase( const QString& styleId, QString &msgError /Out/ ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think /Out/
parameters make mostly sense if the return value is already used for something else. Could we use the return value instead here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 @m-kuhn I generally prefer an explicit bool as return success/fail value instead of hiding error in the msgError value Null or !Null, btw I don't have a stronger opinion on that.
I agree that if msgError is usdes, it can be the return value of the function. I suppose @jgrocha followed the same style as in getStyleFromDatabase where the return is the style string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @m-kuhn and @luipir for the comments.
I've followed the saveStyleToDatabase
signature, to make deleteStyleFromDatabase
as similar as possible.
But I agree that it does make sense to have deleteStyleFromDatabase
returning a bool value, to indicate the success of the operation.
So, I added a bool
returning value and removed the /Out/
parameter from sip.
tnx @jgrocha to add this new test |
python/core/qgsvectorlayer.sip
Outdated
@@ -685,6 +685,11 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator | |||
virtual QString getStyleFromDatabase( const QString& styleId, QString &msgError /Out/ ); | |||
|
|||
/** | |||
* Will delete the named style corresponding to style id provided from the database | |||
*/ | |||
virtual bool deleteStyleFromDatabase( const QString& styleId, QString &msgError ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You still need to leave the /Out/
annotation in place or the error message will not be accessible in python
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @m-kuhn . I misinterpreted your previous comment.
I've put back the msgError
available using SIP. I've adjust the python tests according to this signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jgrocha , looks good now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just done a quick review of the code style. I haven't tested this or made any functionality comments (@luipir has already covered these thoroughly!). Overall looks good to me, just some minor changes requested.
src/app/qgsloadstylefromdbdialog.cpp
Outdated
mSelectedStyleId = QLatin1String( "" ); | ||
mSelectedStyleName = QLatin1String( "" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line (and also the one above it) isn't required. Qstrings will always be initialised to an empty string.
* It returns false by default. | ||
* Must be implemented by providers that support delete styles from db returning true | ||
*/ | ||
virtual bool isDeleteStyleFromDBSupported() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: replace all use of "DB" in API with "Db" or "database"
src/app/qgsloadstylefromdbdialog.cpp
Outdated
connect( mRelatedTable, SIGNAL( doubleClicked( QModelIndex ) ), this, SLOT( accept() ) ); | ||
connect( mOthersTable, SIGNAL( doubleClicked( QModelIndex ) ), this, SLOT( accept() ) ); | ||
connect( mCancelButton, SIGNAL( clicked() ), this, SLOT( reject() ) ); | ||
connect( mDeleteButton, SIGNAL( clicked() ), this, SLOT( deleteStyleFromDB() ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We require use of new style qt connects in all new code - see qgis/QGIS-Enhancement-Proposals#77 for details and the motivation behind this change.
src/app/qgsloadstylefromdbdialog.cpp
Outdated
QTableWidgetItem *item; | ||
QList<QTableWidgetItem *> selected = styleTable->selectedItems(); | ||
|
||
if ( selected.count() > 0 ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!selected.isEmpty()
(Using isEmpty makes the meaning of this check immediately obvious)
src/app/qgsloadstylefromdbdialog.cpp
Outdated
} | ||
else | ||
{ | ||
mSelectedStyleName = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mSelectedStyleName.clear()
(More efficient then construction of the empty string)
src/app/qgsloadstylefromdbdialog.h
Outdated
|
||
private: | ||
QgsVectorLayer *mLayer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a quick glance it seems this isn't initialised. Can you change this to:
QgsVectorLayer* mLayer = nullptr;
src/core/qgsvectorlayer.cpp
Outdated
bool QgsVectorLayer::deleteStyleFromDatabase( const QString& styleId, QString &msgError ) | ||
{ | ||
QgsProviderRegistry * pReg = QgsProviderRegistry::instance(); | ||
QLibrary *myLib = pReg->providerLibrary( mProviderKey ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use
QScopedPointer here
Otherwise this function leaks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @nyalldawson. I don't understand your comment. Where should I use QScopedPointer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change it to:
{
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 );
}
When the scoped pointer goes out of scope, the associated pointer is automatically deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @nyalldawson.
The pattern I was using (without the QScopedPointer
) is still used on many places. I've updated all usages of the old pattern just in src/core/qgsvectorlayer.cpp
to this more safer alternative, using QScopedPointer
without an explicit delete of the pointer.
src/core/qgsvectorlayer.h
Outdated
@@ -786,6 +786,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte | |||
virtual QString getStyleFromDatabase( const QString& styleId, QString &msgError ); | |||
|
|||
/** | |||
* Will delete the named style corresponding to style id provided from the database |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a "@note added in QGIS 3.0" to all newly added public/protected members? (This helps plugin devs know what API calls they can safely use)
…ls#77 Changed isDeleteStyleFromDBSupported to isDeleteStyleFromDbSupported
Thanks @jgrocha - I'll just wait for the Travis build results and then merge |
Great work - thank you! |
Thanks @nyalldawson. I've learned a lot. |
Hi,
As already been discussed on the mailing list there was no way to remove a saved style from the database.
This PR adds the possibility to remove a style from the database, just for the postgres provider, for now.
Each provider has a new method
virtual bool isDeleteStyleFromDBSupported()
which return false until we add this functionality to it. Onlyqgspostgresprovider
returnstrue
and implementsQgsPostgresProvider::deleteStyleById
.If the provider does not support this feature, the delete button is hidden from the interface.
The dialog for load and delete styles looks almost the same. It has a new title and a new delete button. The buttons (delete and load) are only enabled when a style is selected.
After deleting the style from the database, instead of just remove the row from the interface, I am reading the style again from the database. The reason is that this kind of provider is used in environments with multiple users that might have added, deleted of updated the styles in the meanwhile.
Feedback is very welcome. I would like thank @luipir and @nyalldawson the feedback already sent on the mailing list.
The changes might have small impact on the documentation. Should I do something about it or it will be managed by the documentation team?