X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/55a9aa18d2ddd2688eeb59d962ed60067bbd9f6c..bd839796f1e165016f8a4dfd01b222b31fb7773f:/src/views/draganddrophelper.cpp diff --git a/src/views/draganddrophelper.cpp b/src/views/draganddrophelper.cpp index 9708415f0..7b9949df4 100644 --- a/src/views/draganddrophelper.cpp +++ b/src/views/draganddrophelper.cpp @@ -1,182 +1,100 @@ -/*************************************************************************** - * Copyright (C) 2007 by Peter Penz * - * Copyright (C) 2007 by David Faure * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ +/* + * SPDX-FileCopyrightText: 2007-2011 Peter Penz + * SPDX-FileCopyrightText: 2007 David Faure + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "draganddrophelper.h" -#include -#include -#include -#include -#include +#include +#include -#include "views/dolphiniconsview.h" -#include "views/dolphinviewcontroller.h" +#include +#include +#include +#include -#include -#include -#include -#include -#include +QHash DragAndDropHelper::m_urlListMatchesUrlCache; -class DragAndDropHelperSingleton +bool DragAndDropHelper::urlListMatchesUrl(const QList &urls, const QUrl &destUrl) { -public: - DragAndDropHelper instance; -}; -K_GLOBAL_STATIC(DragAndDropHelperSingleton, s_dragAndDropHelper) + auto iteratorResult = m_urlListMatchesUrlCache.constFind(destUrl); + if (iteratorResult != m_urlListMatchesUrlCache.constEnd()) { + return *iteratorResult; + } -DragAndDropHelper& DragAndDropHelper::instance() -{ - return s_dragAndDropHelper->instance; + const bool destUrlMatches = std::find_if(urls.constBegin(), + urls.constEnd(), + [destUrl](const QUrl &url) { + return url.matches(destUrl, QUrl::StripTrailingSlash); + }) + != urls.constEnd(); + + return *m_urlListMatchesUrlCache.insert(destUrl, destUrlMatches); } -void DragAndDropHelper::startDrag(QAbstractItemView* itemView, - Qt::DropActions supportedActions, - DolphinViewController* dolphinViewController) +KIO::DropJob *DragAndDropHelper::dropUrls(const QUrl &destUrl, QDropEvent *event, QWidget *window) { - // Do not start a new drag until the previous one has been finished. - // This is a (possibly temporary) fix for bug #187884. - static bool isDragging = false; - if (isDragging) { - return; - } - isDragging = true; - - const QModelIndexList indexes = itemView->selectionModel()->selectedIndexes(); - if (!indexes.isEmpty()) { - QMimeData *data = itemView->model()->mimeData(indexes); - if (data == 0) { - return; + const QMimeData *mimeData = event->mimeData(); + if (isArkDndMimeType(mimeData)) { + const QString remoteDBusClient = QString::fromUtf8(mimeData->data(arkDndServiceMimeType())); + const QString remoteDBusPath = QString::fromUtf8(mimeData->data(arkDndPathMimeType())); + + QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, + remoteDBusPath, + QStringLiteral("org.kde.ark.DndExtract"), + QStringLiteral("extractSelectedFilesTo")); + message.setArguments({destUrl.toDisplayString(QUrl::PreferLocalFile)}); + QDBusConnection::sessionBus().call(message); + } else { + if (urlListMatchesUrl(event->mimeData()->urls(), destUrl)) { + return nullptr; } - if (dolphinViewController != 0) { - dolphinViewController->requestToolTipHiding(); + // TODO: remove this check once Qt is fixed so that it doesn't emit a QDropEvent on Wayland + // when we called QDragMoveEvent::ignore() + // https://codereview.qt-project.org/c/qt/qtwayland/+/541750 + KFileItem item(destUrl); + // KFileItem(QUrl) only stat local URLs, so we always allow dropping on non-local URLs + if (!item.isLocalFile() || supportsDropping(item)) { + // Drop into a directory or a desktop-file + KIO::DropJob *job = KIO::drop(event, destUrl); + KJobWidgets::setWindow(job, window); + return job; } - - QDrag* drag = new QDrag(itemView); - drag->setPixmap(createDragPixmap(itemView)); - drag->setMimeData(data); - - m_dragSource = itemView; - drag->exec(supportedActions, Qt::IgnoreAction); - m_dragSource = 0; } - isDragging = false; + + return nullptr; } -bool DragAndDropHelper::isDragSource(QAbstractItemView* itemView) const +bool DragAndDropHelper::supportsDropping(const KFileItem &destItem) { - return (m_dragSource != 0) && (m_dragSource == itemView); + return (destItem.isDir() && destItem.isWritable()) || destItem.isDesktopFile(); } -void DragAndDropHelper::dropUrls(const KFileItem& destItem, - const KUrl& destPath, - QDropEvent* event, - QWidget* widget) +void DragAndDropHelper::updateDropAction(QDropEvent *event, const QUrl &destUrl) { - const bool dropToItem = !destItem.isNull() && (destItem.isDir() || destItem.isDesktopFile()); - const KUrl destination = dropToItem ? destItem.url() : destPath; - - const QMimeData* mimeData = event->mimeData(); - if (mimeData->hasFormat("application/x-kde-dndextract")) { - QString remoteDBusClient = mimeData->data("application/x-kde-dndextract"); - QDBusMessage message = QDBusMessage::createMethodCall(remoteDBusClient, "/DndExtract", - "org.kde.DndExtract", "extractSelectedFilesTo"); - message.setArguments(QVariantList() << destination.path()); - QDBusConnection::sessionBus().call(message); + if (urlListMatchesUrl(event->mimeData()->urls(), destUrl)) { + event->setDropAction(Qt::IgnoreAction); + event->ignore(); + } + KFileItem item(destUrl); + if (!item.isLocalFile() || supportsDropping(item)) { + event->setDropAction(event->proposedAction()); + event->accept(); } else { - const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); - const int urlsCount = urls.count(); - if ((urlsCount == 1) && (urls.first() == destination)) { - emit errorMessage(i18nc("@info:status", "A folder cannot be dropped into itself")); - } else if (dropToItem) { - KonqOperations::doDrop(destItem, destination, event, widget); - } else { - KonqOperations::doDrop(KFileItem(), destination, event, widget); - } + event->setDropAction(Qt::IgnoreAction); + event->ignore(); } } -DragAndDropHelper::DragAndDropHelper() - : m_dragSource(0) +void DragAndDropHelper::clearUrlListMatchesUrlCache() { + DragAndDropHelper::m_urlListMatchesUrlCache.clear(); } -QPixmap DragAndDropHelper::createDragPixmap(QAbstractItemView* itemView) const +bool DragAndDropHelper::isArkDndMimeType(const QMimeData *mimeData) { - const QModelIndexList selectedIndexes = itemView->selectionModel()->selectedIndexes(); - Q_ASSERT(!selectedIndexes.isEmpty()); - - QAbstractProxyModel* proxyModel = static_cast(itemView->model()); - KDirModel* dirModel = static_cast(proxyModel->sourceModel()); - - const int itemCount = selectedIndexes.count(); - - // If more than one item is dragged, align the items inside a - // rectangular grid. The maximum grid size is limited to 5 x 5 items. - int xCount = 3; - int size = KIconLoader::SizeMedium; - if (itemCount > 16) { - xCount = 5; - size = KIconLoader::SizeSmall; - } else if (itemCount > 9) { - xCount = 4; - size = KIconLoader::SizeSmallMedium; - } - - if (itemCount < xCount) { - xCount = itemCount; - } - - int yCount = itemCount / xCount; - if (itemCount % xCount != 0) { - ++yCount; - } - if (yCount > xCount) { - yCount = xCount; - } - - // Draw the selected items into the grid cells - QPixmap dragPixmap(xCount * size + xCount - 1, yCount * size + yCount - 1); - dragPixmap.fill(Qt::transparent); - - QPainter painter(&dragPixmap); - int x = 0; - int y = 0; - foreach (const QModelIndex& selectedIndex, selectedIndexes) { - const QModelIndex index = proxyModel->mapToSource(selectedIndex); - const KFileItem item = dirModel->itemForIndex(index); - const QPixmap pixmap = item.pixmap(size, size); - painter.drawPixmap(x, y, pixmap); - - x += size + 1; - if (x >= dragPixmap.width()) { - x = 0; - y += size + 1; - } - if (y >= dragPixmap.height()) { - break; - } - } - - return dragPixmap; + return mimeData->hasFormat(arkDndServiceMimeType()) && mimeData->hasFormat(arkDndPathMimeType()); } - -#include "draganddrophelper.moc"