Accept file drops across the channel footer

This commit is contained in:
evgeny committed 2026-10-09 23:30:33 +02:00
1 parent b631c4ed72
commit 49ee66d49c
3 files changed
+63

No files matched your search

+50
View File
@@ -13,6 +13,9 @@
#include <QMouseEvent>
#include <QMenu>
#include <QStyle>
#include <QDropEvent>
#include <QMimeData>
#include <QUrl>
extern "C" {
#include "../../lib/debug_config.h"
@@ -175,6 +178,7 @@ ChannelList::ChannelList(DbManager* db, QWidget *parent)
layout->addWidget(m_listView);
auto *footer = new QWidget(this);
m_footer = footer; m_footer->setObjectName("channelFooter");
auto *fl = new QHBoxLayout(footer);
fl->setContentsMargins(6, 4, 6, 4);
fl->setSpacing(6);
@@ -240,6 +244,12 @@ ChannelList::ChannelList(DbManager* db, QWidget *parent)
fl->addWidget(plusBtn);
layout->addWidget(footer);
auto targets = footer->findChildren<QWidget*>(); targets.append(footer);
for (auto* target : targets) { target->setAcceptDrops(true); target->installEventFilter(this); }
m_dropHint = new QLabel(footer); m_dropHint->setObjectName("ownFilesDropHint");
m_dropHint->setAttribute(Qt::WA_TransparentForMouseEvents); m_dropHint->setAlignment(Qt::AlignCenter);
m_dropHint->setStyleSheet("QLabel { border: 2px dashed palette(highlight); background: palette(window); color: palette(text); }");
m_dropHint->hide();
connect(m_listView->selectionModel(), &QItemSelectionModel::currentChanged,
this, [this](const QModelIndex &current, const QModelIndex &) {
@@ -266,6 +276,46 @@ ChannelList::ChannelList(DbManager* db, QWidget *parent)
});
}
bool ChannelList::eventFilter(QObject* target, QEvent* event) {
if (event->type() == QEvent::DragLeave) { m_dropHint->hide(); return true; }
if (event->type() != QEvent::DragEnter && event->type() != QEvent::DragMove && event->type() != QEvent::Drop)
return QWidget::eventFilter(target, event);
auto* drop = static_cast<QDropEvent*>(event);
QString channel = m_listView->currentIndex().data(ChannelChannelIdRole).toString();
QString reason;
if (!channel.toULongLong()) reason = QCoreApplication::translate("ChatGui", "Select a group to upload files");
else if (!m_db || !m_db->myNodeId() || !gui_bridge_is_uasync_ready())
reason = QCoreApplication::translate("ChatGui", "Upload unavailable");
else if (!drop->mimeData()->hasUrls() || drop->mimeData()->urls().isEmpty() || !(drop->possibleActions() & Qt::CopyAction))
reason = QCoreApplication::translate("ChatGui", "Drop local files to copy");
QStringList paths;
if (reason.isEmpty()) for (const auto& url : drop->mimeData()->urls()) {
if (!url.isLocalFile() || url.toLocalFile().isEmpty()) {
reason = QCoreApplication::translate("ChatGui", "Only local files can be uploaded"); break;
}
paths.append(url.toLocalFile());
}
if (event->type() == QEvent::Drop) m_dropHint->hide();
else {
m_dropHint->setGeometry(m_footer->rect());
m_dropHint->setText(reason.isEmpty() ? QCoreApplication::translate("ChatGui", "Copy to my files") : reason);
m_dropHint->show(); m_dropHint->raise();
}
if (!reason.isEmpty()) {
if (event->type() != QEvent::DragMove)
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file drop: rejected channel=%s reason=%s", qPrintable(channel), qPrintable(reason));
drop->ignore();
// После отклонённого DragEnter Qt не гарантирует DragLeave.
m_dropHint->hide(); return true;
}
drop->setDropAction(Qt::CopyAction); drop->accept();
if (event->type() == QEvent::Drop) {
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file drop: accepted channel=%s files=%d", qPrintable(channel), int(paths.size()));
QTimer::singleShot(0, this, [this, channel, paths] { emit ownFilesDropped(channel, paths); });
}
return true;
}
void ChannelList::refreshDmPresence() {
if (!m_dmPresenceTimer->isActive()) m_dmPresenceTimer->start();
}