Skip to content
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

Merged
merged 14 commits into from Jan 8, 2019
Merged

Conversation

signedav
Copy link
Contributor

With right click on the browser the action is "Delete Selected Tables" in case there are more than one selected. This is implemented for:

  • GeoPackage
  • SpatiaLite
  • PostGIS
  • MSSQL (including. "Truncate Selected Tables")

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

@nyalldawson
Copy link
Collaborator

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

@signedav
Copy link
Contributor Author

Thanks @nyalldawson I have overseen that. I will update the implementation...

implemented for derived functions in:
- `QgsGeoPackageAbstractLayerItem`
- `QgsSLLayerItem`
- `QgsPGLayerItem`
- `QgsMssqlLayerItem`
@signedav
Copy link
Contributor Author

Implemented now over the api mentioned by @nyalldawson
Means it calls for each selected item the derived deleteLayer(). Means the delete-action is removed from:

  • QgsGeoPackageAbstractLayerItem
  • QgsSLLayerItem
  • QgsPGLayerItem
  • QgsMssqlLayerItem

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 deleteLayer() function. Should I object_cast the QgsDataItems or is there a type handling for that I've overlooked?

PS. I only cared about delete layer and not truncate, rename etc. for QgsPGLayerItems and QgsMssqlLayerItem. Does this need to be part for this PR as well?

@@ -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();
Copy link
Collaborator

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

@nyalldawson
Copy link
Collaborator

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 deleteLayer() function. Should I object_cast the QgsDataItems or is there a type handling for that I've overlooked?

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.

@nyalldawson nyalldawson added this to the 3.6 milestone Nov 21, 2018
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 );
Copy link
Collaborator

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).

Copy link
Collaborator

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.

Copy link
Contributor Author

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?

Copy link
Member

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).

Copy link
Collaborator

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.

Copy link
Member

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. :/

Copy link
Collaborator

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

  1. 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
  2. only show the messagebox failure message after all items have been processed

@stale
Copy link

stale bot commented Dec 25, 2018

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

  • that all unit tests are passing

  • that all comments by reviewers have been addressed

  • that there is enough information for reviewers, in particular

    • link to any issues which this pull request fixes

    • add a description of workflows which this pull request fixes

    • add screenshots if applicable

  • that you have written unit tests where possible
    In case you should have any uncertainty, please leave a comment and we will be happy to help you proceed with this pull request.
    If there is no further activity on this pull request, it will be closed in a week.

@stale stale bot added the stale Uh oh! Seems this work is abandoned, and the PR is about to close. label Dec 25, 2018
@signedav
Copy link
Contributor Author

I'll do that on the begin of next year

@stale stale bot removed the stale Uh oh! Seems this work is abandoned, and the PR is about to close. label Dec 25, 2018
@signedav
Copy link
Contributor Author

signedav commented Jan 3, 2019

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.

src/app/browser/qgsinbuiltdataitemproviders.cpp Outdated Show resolved Hide resolved
src/app/browser/qgsinbuiltdataitemproviders.cpp Outdated Show resolved Hide resolved
src/core/qgsbrowsermodel.h Outdated Show resolved Hide resolved
@nyalldawson
Copy link
Collaborator

Looks good -- I can't see any remaining issues here, thanks!

@m-kuhn m-kuhn merged commit 5df5c37 into qgis:master Jan 8, 2019
@signedav
Copy link
Contributor Author

signedav commented Jan 8, 2019

Thanks @nyalldawson and @m-kuhn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants