|
|
|
|
@ -24,6 +24,7 @@
|
|
|
|
|
#include <QDrag> |
|
|
|
|
#include <QMouseEvent> |
|
|
|
|
#include <QScopeGuard> |
|
|
|
|
#include <QChildEvent> |
|
|
|
|
#include <functional> |
|
|
|
|
extern "C" { |
|
|
|
|
#include "member_files/member_files.h" |
|
|
|
|
@ -77,6 +78,20 @@ static QPushButton* cancelButton(MemberFileBrowser& browser) {
|
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Offscreen не имеет native drag. Получатель запрашивает реальный MIME при публикации QDrag приложению.
|
|
|
|
|
class DragReceiver : public QObject { |
|
|
|
|
public: |
|
|
|
|
std::function<void(const QMimeData*)> receive; |
|
|
|
|
protected: |
|
|
|
|
bool eventFilter(QObject* object, QEvent* event) override { |
|
|
|
|
if (object == QCoreApplication::instance() && event->type() == QEvent::ChildAdded) { |
|
|
|
|
auto* drag = qobject_cast<QDrag*>(static_cast<QChildEvent*>(event)->child()); |
|
|
|
|
if (drag && drag->mimeData()) receive(drag->mimeData()); |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class BrowserTest : public QObject { |
|
|
|
|
Q_OBJECT |
|
|
|
|
private slots: |
|
|
|
|
@ -87,7 +102,15 @@ private slots:
|
|
|
|
|
} |
|
|
|
|
void init() { transfers.clear(); cancelled.clear(); ready = true; transferStarted = {}; } |
|
|
|
|
|
|
|
|
|
void exportToSystemClipboardAndSingleDrag_data() { |
|
|
|
|
QTest::addColumn<int>("dragStatus"); |
|
|
|
|
QTest::newRow("success") << int(MF_OK); |
|
|
|
|
QTest::newRow("failure") << int(MF_IO_ERROR); |
|
|
|
|
QTest::newRow("cancel") << int(MF_CANCELLED); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void exportToSystemClipboardAndSingleDrag() { |
|
|
|
|
QFETCH(int, dragStatus); |
|
|
|
|
QTemporaryDir cache; QVERIFY(cache.isValid()); QByteArray oldCache = qgetenv("XDG_CACHE_HOME"); |
|
|
|
|
qputenv("XDG_CACHE_HOME", cache.path().toUtf8()); |
|
|
|
|
auto restoreCache = qScopeGuard([oldCache] { qputenv("XDG_CACHE_HOME", oldCache); QApplication::clipboard()->clear(); }); |
|
|
|
|
@ -127,24 +150,29 @@ private slots:
|
|
|
|
|
QCOMPARE(QApplication::clipboard()->text(), QString("keep on error")); |
|
|
|
|
|
|
|
|
|
bool committed = false, received = false; |
|
|
|
|
transferStarted = [&browser, &committed](mf_transfer_request transfer) { |
|
|
|
|
QTimer::singleShot(50, &browser, [&browser, &committed, transfer] { |
|
|
|
|
QFile file(QString::fromUtf8(transfer.local)); QVERIFY(file.open(QIODevice::WriteOnly)); |
|
|
|
|
QCOMPARE(file.write("drag bytes"), 10LL); file.close(); committed = true; complete(browser, transfer); |
|
|
|
|
transferStarted = [&browser, &committed, dragStatus](mf_transfer_request transfer) { |
|
|
|
|
QTimer::singleShot(50, &browser, [&browser, &committed, transfer, dragStatus] { |
|
|
|
|
if (!dragStatus) { |
|
|
|
|
QFile file(QString::fromUtf8(transfer.local)); QVERIFY(file.open(QIODevice::WriteOnly)); |
|
|
|
|
QCOMPARE(file.write("drag bytes"), 10LL); file.close(); |
|
|
|
|
} |
|
|
|
|
committed = true; |
|
|
|
|
if (dragStatus == MF_CANCELLED) cancelButton(browser)->click(); |
|
|
|
|
complete(browser, transfer, dragStatus); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
QTimer receiver; receiver.setInterval(5); |
|
|
|
|
connect(&receiver, &QTimer::timeout, &browser, [&] { |
|
|
|
|
auto* drag = QCoreApplication::instance()->findChild<QDrag*>(); |
|
|
|
|
if (!drag || !drag->mimeData()) return; |
|
|
|
|
receiver.stop(); auto* data = drag->mimeData(); |
|
|
|
|
DragReceiver receiver; |
|
|
|
|
receiver.receive = [&](const QMimeData* data) { |
|
|
|
|
QVERIFY(data->hasUrls()); QVERIFY(!committed); |
|
|
|
|
// Запрос системного менеджера приходит до скачивания и возвращается лишь после commit.
|
|
|
|
|
auto urls = data->urls(); QVERIFY(committed); QCOMPARE(urls.size(), 1); |
|
|
|
|
QFile file(urls.first().toLocalFile()); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(file.readAll(), QByteArray("drag bytes")); |
|
|
|
|
received = true; QDrag::cancel(); |
|
|
|
|
}); |
|
|
|
|
receiver.start(); |
|
|
|
|
auto urls = data->urls(); QVERIFY(committed); |
|
|
|
|
if (!dragStatus) { |
|
|
|
|
QCOMPARE(urls.size(), 1); QFile file(urls.first().toLocalFile()); |
|
|
|
|
QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(file.readAll(), QByteArray("drag bytes")); |
|
|
|
|
} else QVERIFY(urls.isEmpty()); |
|
|
|
|
received = true; |
|
|
|
|
}; |
|
|
|
|
QCoreApplication::instance()->installEventFilter(&receiver); |
|
|
|
|
QTimer::singleShot(3000, &browser, [] { QDrag::cancel(); }); |
|
|
|
|
tree->setFocus(); QCoreApplication::processEvents(); QPoint point = tree->visualItemRect(item).center(); |
|
|
|
|
QTest::mousePress(tree->viewport(), Qt::LeftButton, Qt::NoModifier, point); |
|
|
|
|
|