diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -71,7 +71,7 @@ * the root-parent of all items. * @see rootItem() */ - QUrl directory() const; + QUrl directory() const Q_DECL_OVERRIDE; /** * Cancels the loading of a directory which has been started by either @@ -80,6 +80,9 @@ void cancelDirectoryLoading(); virtual int count() const Q_DECL_OVERRIDE; + + QUrl indexGetUrl(int index) const Q_DECL_OVERRIDE; + virtual QHash data(int index) const Q_DECL_OVERRIDE; virtual bool setData(int index, const QHash& values) Q_DECL_OVERRIDE; diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -2347,3 +2347,7 @@ return true; } + +QUrl KFileItemModel::indexGetUrl(int index) const { + return fileItem(index).url(); +} diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -257,6 +257,11 @@ void startDragging(); /** + * @return True, if destUrl is contained in the url list. + */ + bool urlListMatchesUrl(const QList &urls, const QUrl& destUrl); + + /** * @return Widget that is currently in the hovered state. 0 is returned * if no widget is marked as hovered. */ diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -882,6 +882,10 @@ if (!droppingBetweenItems) { if (m_model->supportsDropping(index)) { // Something has been dragged on an item. + + // check if the we're dragging the same item onto itself. + event->setAccepted(!urlListMatchesUrl(event->mimeData()->urls(), m_model->indexGetUrl(index))); + m_view->hideDropIndicator(); if (!newHoveredWidget->isHovered()) { newHoveredWidget->setHovered(true); @@ -901,6 +905,9 @@ } } } else { + // We're hovering over the directory, check if we're dropping onto itself. + event->setAccepted(!urlListMatchesUrl(event->mimeData()->urls(), m_model->directory())); + m_view->hideDropIndicator(); } @@ -1326,3 +1333,13 @@ } } +bool KItemListController::urlListMatchesUrl(const QList &urls, const QUrl &destUrl) { + foreach(QUrl url, urls) { + if (url.matches(destUrl, QUrl::StripTrailingSlash)) { + return true; + } + } + + return false; +} + diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -268,6 +268,17 @@ bool isHeaderVisible() const; /** + * On a drag n' drop operation this should be set to the item last hovered + */ + void setDropUrl(const QUrl& value); + + /** + * When a drag n' drop operation starts this should contain the list + * of the selected items. + */ + void setDragSource(const QList& dragSource); + + /** * @return Header of the list. The header is also available if it is not shown * (see KItemListView::setHeaderShown()). */ @@ -705,6 +716,8 @@ static int itemsPerSize(qreal size, qreal itemSize, qreal itemMargin); private: + QUrl m_dropUrl; + QList m_dragSource; bool m_enabledSelectionToggles; bool m_grouped; bool m_supportsItemExpanding; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -44,6 +44,7 @@ #include #include +#include #include "kitemlistviewaccessible.h" @@ -936,12 +937,13 @@ void KItemListView::dragEnterEvent(QGraphicsSceneDragDropEvent* event) { - event->setAccepted(true); setAutoScroll(true); } void KItemListView::dragMoveEvent(QGraphicsSceneDragDropEvent* event) { + event->setAccepted(!m_dragSource.contains(m_dropUrl)); + QGraphicsWidget::dragMoveEvent(event); m_mousePos = transform().map(event->pos()); @@ -2672,7 +2674,15 @@ return count; } +void KItemListView::setDropUrl(const QUrl& value) +{ + m_dropUrl = value; +} +void KItemListView::setDragSource(const QList& dragSource) +{ + m_dragSource = dragSource; +} KItemListCreatorBase::~KItemListCreatorBase() { diff --git a/src/kitemviews/kitemmodelbase.h b/src/kitemviews/kitemmodelbase.h --- a/src/kitemviews/kitemmodelbase.h +++ b/src/kitemviews/kitemmodelbase.h @@ -172,6 +172,16 @@ // decision whether it accepts the drop? virtual bool supportsDropping(int index) const; + /** + * @return URL of the item at the specified index + */ + virtual QUrl indexGetUrl(int index) const; + + /** + * @return Parent directory of the items that are shown + */ + virtual QUrl directory() const; + signals: /** * Is emitted if one or more items have been inserted. Each item-range consists diff --git a/src/kitemviews/kitemmodelbase.cpp b/src/kitemviews/kitemmodelbase.cpp --- a/src/kitemviews/kitemmodelbase.cpp +++ b/src/kitemviews/kitemmodelbase.cpp @@ -159,3 +159,11 @@ Q_UNUSED(previous); } +QUrl KItemModelBase::indexGetUrl(int index) const { + return QUrl(); +} + +QUrl KItemModelBase::directory() const { + return QUrl(); +} + diff --git a/src/panels/places/placesitemmodel.h b/src/panels/places/placesitemmodel.h --- a/src/panels/places/placesitemmodel.h +++ b/src/panels/places/placesitemmodel.h @@ -130,6 +130,9 @@ */ void saveBookmarks(); + QUrl indexGetUrl(int index) const Q_DECL_OVERRIDE; + + signals: void errorMessage(const QString& message); void storageSetupDone(int index, bool success); diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -1164,6 +1164,17 @@ return query.toSearchUrl(); } + +QUrl PlacesItemModel::indexGetUrl(int index) const { + const PlacesItem* item = placesItem(index); + + if (item) { + return item->url(); + } + + return KItemModelBase::indexGetUrl(index); +} + #endif #ifdef PLACESITEMMODEL_DEBUG diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -1014,6 +1014,10 @@ { const KFileItem item = m_model->fileItem(index); + if (m_dragging) { + m_container->controller()->view()->setDropUrl(item.url()); + } + if (GeneralSettings::showToolTips() && !m_dragging) { QRectF itemRect = m_container->controller()->view()->itemContextRect(index); const QPoint pos = m_container->mapToGlobal(itemRect.topLeft().toPoint()); @@ -1030,6 +1034,8 @@ Q_UNUSED(index); hideToolTip(); emit requestItemInfo(KFileItem()); + + m_container->controller()->view()->setDropUrl(QUrl()); } void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event) diff --git a/src/views/draganddrophelper.cpp b/src/views/draganddrophelper.cpp --- a/src/views/draganddrophelper.cpp +++ b/src/views/draganddrophelper.cpp @@ -42,6 +42,13 @@ message.setArguments({destUrl.toDisplayString(QUrl::PreferLocalFile)}); QDBusConnection::sessionBus().call(message); } else { + // Prevent drag and drop onto self + if (mimeData->urls().contains(destUrl)) { + event->ignore(); + + return nullptr; + } + // Drop into a directory or a desktop-file KIO::DropJob *job = KIO::drop(event, destUrl); KJobWidgets::setWindow(job, window);