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 selected tables as DataItem action #8507
Conversation
Is this for master? There's a whole new api for the gui component of data items which was partly designed to cleanly address this -- see #8352 |
Thanks @nyalldawson I have overseen that. I will update the implementation... |
implemented for derived functions in: - `QgsGeoPackageAbstractLayerItem` - `QgsSLLayerItem` - `QgsPGLayerItem` - `QgsMssqlLayerItem`
Implemented now over the api mentioned by @nyalldawson
I hope I use it like it's intendet. Not sure yet how I provide that the action is only shown for the relevant items, that have a derived PS. I only cared about delete layer and not truncate, rename etc. for |
src/core/qgsdataitem.h
Outdated
@@ -323,6 +323,9 @@ class CORE_EXPORT QgsDataItem : public QObject | |||
//! Move object and all its descendants to thread | |||
void moveToThread( QThread *targetThread ); | |||
|
|||
//! Delete this layer item | |||
virtual bool deleteLayer(); |
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 this belongs in the QgsLayerItem subclass
You could also add a "DeleteLayer" capability to the QgsDataItem::Capability enum, and then only return this flag for layer items which support delete. I think that's the cleanest approach here. |
check if the item with the menu has this capability and only handle the selected items with this capabiltiy
QAction *deleteAction = new QAction( deleteText, menu ); | ||
connect( deleteAction, &QAction::triggered, this, [ = ] | ||
{ | ||
deleteLayers( selectedDeletableItems ); |
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 is likely to result in crashes, because after the first table is deleted providers may (and usually will) trigger a refresh of their parent. This happens in a background thread, and may result in items within the selectedDeletableItems list being deleted before deleteLayers has had a chance to handle them. I think what should be done here is that selectedDeletableItems will need to be a string list, storing the paths of the selected items instead of the items themselves. (I've experienced this crash myself when deleting OGR items, which was why the OGR provider was adapted to use a static deleteLayer method with strings instead of the layer item).
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.
And my apologies, I should have picked this up in the earlier review. That's my fault.
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.
Hm... Good point.
Can't we just check, if the item is still valid before we call to delete it?
If I understand you correctly, it means, that it shouldn't be implemented in the specific layer items and have a general deleteItemAccordingUri( item-uri, item-type )
function in qgsinbuiltdataitemproviders
?
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 is likely to result in crashes, because after the first table is deleted providers may (and usually will) trigger a refresh of their parent. This happens in a background thread, and may result in items within the selectedDeletableItems list being deleted before deleteLayers has had a chance to handle them.
I'm not sure I can follow this logic @nyalldawson
Does this mean, a background thread deletes items from the UI? If yes, this sounds like a guarantee for crashes and should be fixed directly instead of working around potential issues here.
Instead they should be deleted (via queued connection) on the main thread, in which case they will be deleted after this code has been executed (because this code is triggered by the UI on the main thread and executed via direct connection unless I'm mistaken).
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.
Instead they should be deleted (via queued connection) on the main thread
I believe this is already the case
in which case they will be deleted after this code has been executed (because this code is triggered by the UI on the main thread and executed via direct connection unless I'm mistaken).
Ideally yes, but in practice there must be some processEvents calls or something messing things up, because I definitely got easily reproducible crashes when this approach was used in the OGR provider.
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.
Is there a stacktrace around for this or instructions how to reproduce this?
To be honest, I'm not a big fan of implementing workarounds for badly designed code without seeing it first and having a good ground to decide that fixing the broken code is (much) harder than implementing the workaround. :/
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's 7ad1d29 -- and that commit gives more clues, because it's while the confirmation dialog is shown (main thread) that the main thread event loop is running and deleting the items due to the previously queued refresh.
So that's all good -- no nasty bugs in master which we're hiding. But this PR also has messageboxes showing while deleting layers (confirmation for each layer, failure warning) and so needs to handle that same case. Approaches would be encapsulating the layer parameters from all items in advance and only using these during the delete, OR
- show a single confirmation once in advance showing a summary of all layers to be deleted, and not show a confirmation for each individual layer in turn, and
- only show the messagebox failure message after all items have been processed
The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check
|
I'll do that on the begin of next year |
I store now the uris in a list, pass the list to the delete-function and there I get the items from the browser model according to the uri. I hope this solves the issue @nyalldawson is reporting. I'm not completely sure if this matches to your suggestion. |
Looks good -- I can't see any remaining issues here, thanks! |
Thanks @nyalldawson and @m-kuhn |
With right click on the browser the action is "Delete Selected Tables" in case there are more than one selected. This is implemented for:
On right click on a (e.g.) GeoPackage and "Delete selected layers" only the selected GeoPackage-tables are deleted. If there are other selected layers the action for them is ignored.
Couldn't test with MSSQL - just implemented it the way like in the other items.
This implements https://issues.qgis.org/issues/19875