From c85ca114553c198af79eedacdb6b40ac4cab20e0 Mon Sep 17 00:00:00 2001 From: Elvis Angelaccio Date: Fri, 21 Apr 2017 13:16:05 +0200 Subject: [PATCH] Ignore drops-onto-items from invalid places items If the QMimeData object created by PlacesItemModel doesn't have any url set (e.g. when dragging unmounted devices), it is detected by the resulting DropJob as "drop raw data" because the mimeData has one format set (the internalMimeType() used for dragging between places items). This results in a crash because the DropJob schedules a PasteJob, but in the meantime the QDrag from Dolphin ends and deletes the mimeData object that was passed to the paste job. The fix is to prevent the DropJob in the first place. We can introduce a new internal mimetype that we use to blacklist drops-onto-items (while still allowing drops-between-items). This way PlacesItemModel can set the blacklist flag if the mimeData is being created without urls. BUG: 373005 FIXED-IN: 17.04.3 Test Plan: Drag and drop an unmounted device to another place item or the DolphinView, doesn't crash anymore. Dropping the unmounted device between two places item still works. Differential Revision: https://phabricator.kde.org/D5535 --- src/kitemviews/kitemlistcontroller.cpp | 2 +- src/kitemviews/kitemmodelbase.cpp | 5 +++++ src/kitemviews/kitemmodelbase.h | 10 ++++++++++ src/panels/places/placesitemmodel.cpp | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index a959697710..3731895d0a 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -928,7 +928,7 @@ bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QT // Something has been dropped between two items. m_view->hideDropIndicator(); emit aboveItemDropEvent(dropAboveIndex, event); - } else { + } else if (!event->mimeData()->hasFormat(m_model->blacklistItemDropEventMimeType())) { // Something has been dropped on an item or on an empty part of the view. emit itemDropEvent(m_view->itemAt(pos), event); } diff --git a/src/kitemviews/kitemmodelbase.cpp b/src/kitemviews/kitemmodelbase.cpp index bf41b1c84b..ee7e81084a 100644 --- a/src/kitemviews/kitemmodelbase.cpp +++ b/src/kitemviews/kitemmodelbase.cpp @@ -142,6 +142,11 @@ bool KItemModelBase::supportsDropping(int index) const return false; } +QString KItemModelBase::blacklistItemDropEventMimeType() const +{ + return QStringLiteral("application/x-dolphin-blacklist-drop"); +} + void KItemModelBase::onGroupedSortingChanged(bool current) { Q_UNUSED(current); diff --git a/src/kitemviews/kitemmodelbase.h b/src/kitemviews/kitemmodelbase.h index bd5ca1d652..45ad1f61ab 100644 --- a/src/kitemviews/kitemmodelbase.h +++ b/src/kitemviews/kitemmodelbase.h @@ -172,6 +172,16 @@ public: // decision whether it accepts the drop? virtual bool supportsDropping(int index) const; + /** + * @return An internal mimetype to signal that an itemDropEvent() should be rejected by + * the receiving model. + * + * This mimeType can be used in createMimeData() to notify that the + * drop-onto-items events should be ignored, while the drop-between-items + * ones should be still accepted. + */ + QString blacklistItemDropEventMimeType() const; + signals: /** * Is emitted if one or more items have been inserted. Each item-range consists diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp index a4741e7469..04dac81b73 100644 --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -376,6 +376,9 @@ QMimeData* PlacesItemModel::createMimeData(const KItemSet& indexes) const QMimeData* mimeData = new QMimeData(); if (!urls.isEmpty()) { mimeData->setUrls(urls); + } else { + // #378954: prevent itemDropEvent() drops if there isn't a source url. + mimeData->setData(blacklistItemDropEventMimeType(), QByteArrayLiteral("true")); } mimeData->setData(internalMimeType(), itemData);