wasm: write file to storage on drop
Change-Id: Ibd1b5d623da07ad611cce577929a23ba991b6738 Pick-to: 6.7 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
8cc84a1386
commit
1f7d222cec
@ -70,16 +70,7 @@ static void qClipboardPasteTo(val event)
|
|||||||
{
|
{
|
||||||
event.call<void>("preventDefault"); // prevent browser from handling drop event
|
event.call<void>("preventDefault"); // prevent browser from handling drop event
|
||||||
|
|
||||||
static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr;
|
QWasmIntegration::get()->getWasmClipboard()->sendClipboardData(event);
|
||||||
dom::DataTransfer transfer(event["clipboardData"]);
|
|
||||||
auto data = transfer.toMimeDataWithFile();
|
|
||||||
if (data->formats().isEmpty())
|
|
||||||
return;
|
|
||||||
// Persist clipboard data so that the app can read it when handling the CTRL+V
|
|
||||||
QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(data,
|
|
||||||
QClipboard::Clipboard);
|
|
||||||
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
|
|
||||||
Qt::ControlModifier, "V");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
|
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
|
||||||
@ -292,4 +283,22 @@ void QWasmClipboard::writeToClipboard()
|
|||||||
document.call<val>("execCommand", val("copy"));
|
document.call<val>("execCommand", val("copy"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QWasmClipboard::sendClipboardData(emscripten::val event)
|
||||||
|
{
|
||||||
|
dom::DataTransfer transfer(event["clipboardData"]);
|
||||||
|
QMimeData *mData;
|
||||||
|
const auto pointerCallback = std::function([&](QMimeData &data) {
|
||||||
|
mData = &data;
|
||||||
|
// Persist clipboard data so that the app can read it when handling the CTRL+V
|
||||||
|
QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(mData,
|
||||||
|
QClipboard::Clipboard);
|
||||||
|
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
|
||||||
|
Qt::ControlModifier, "V");
|
||||||
|
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_V,
|
||||||
|
Qt::ControlModifier, "V");
|
||||||
|
});
|
||||||
|
|
||||||
|
transfer.toMimeDataWithFile(pointerCallback); // mimedata
|
||||||
|
|
||||||
|
}
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -38,6 +38,7 @@ public:
|
|||||||
ProcessKeyboardResult processKeyboard(const KeyEvent &event);
|
ProcessKeyboardResult processKeyboard(const KeyEvent &event);
|
||||||
static void installEventHandlers(const emscripten::val &target);
|
static void installEventHandlers(const emscripten::val &target);
|
||||||
bool hasClipboardApi();
|
bool hasClipboardApi();
|
||||||
|
void sendClipboardData(emscripten::val event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initClipboardPermissions();
|
void initClipboardPermissions();
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "qwasmdom.h"
|
#include "qwasmdom.h"
|
||||||
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QtCore/qpoint.h>
|
#include <QtCore/qpoint.h>
|
||||||
#include <QtCore/qrect.h>
|
#include <QtCore/qrect.h>
|
||||||
#include <QtGui/qimage.h>
|
#include <QtGui/qimage.h>
|
||||||
@ -15,6 +14,9 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
// this needs to live outside the life of DataTransfer
|
||||||
|
Q_GLOBAL_STATIC(QMimeData, resultMimeData);
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
namespace {
|
namespace {
|
||||||
std::string dropActionToDropEffect(Qt::DropAction action)
|
std::string dropActionToDropEffect(Qt::DropAction action)
|
||||||
@ -36,7 +38,9 @@ std::string dropActionToDropEffect(Qt::DropAction action)
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
DataTransfer::DataTransfer(emscripten::val webDataTransfer) : webDataTransfer(webDataTransfer) { }
|
DataTransfer::DataTransfer(emscripten::val webDataTransfer)
|
||||||
|
: webDataTransfer(webDataTransfer) {
|
||||||
|
}
|
||||||
|
|
||||||
DataTransfer::~DataTransfer() = default;
|
DataTransfer::~DataTransfer() = default;
|
||||||
|
|
||||||
@ -78,10 +82,9 @@ void DataTransfer::setDataFromMimeData(const QMimeData &mimeData)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QMimeData *DataTransfer::toMimeDataWithFile()
|
QMimeData *DataTransfer::toMimeDataWithFile(std::function<void(QMimeData &)> callback)
|
||||||
{
|
{
|
||||||
QMimeData *resultMimeData = new QMimeData(); // QScopedPointer?
|
resultMimeData->clear();
|
||||||
|
|
||||||
enum class ItemKind {
|
enum class ItemKind {
|
||||||
File,
|
File,
|
||||||
String,
|
String,
|
||||||
@ -99,8 +102,43 @@ QMimeData *DataTransfer::toMimeDataWithFile()
|
|||||||
case ItemKind::File: {
|
case ItemKind::File: {
|
||||||
m_webFile = item.call<emscripten::val>("getAsFile");
|
m_webFile = item.call<emscripten::val>("getAsFile");
|
||||||
qstdweb::File webfile(m_webFile);
|
qstdweb::File webfile(m_webFile);
|
||||||
QUrl fileUrl(QStringLiteral("file:///") + QString::fromStdString(webfile.name()));
|
if (webfile.size() == 0
|
||||||
uriList.append(fileUrl);
|
|| webfile.size() > 1e+9) { // limit file size to 1 GB
|
||||||
|
qWarning() << "Something happened, File size is" << webfile.size();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QByteArray fileContent(webfile.size(), Qt::Uninitialized);
|
||||||
|
QString mimeFormat = QString::fromStdString(webfile.type());
|
||||||
|
QString fileName = QString::fromStdString(webfile.name());
|
||||||
|
|
||||||
|
// there's a file, now read it
|
||||||
|
webfile.stream(fileContent.data(), [=]() {
|
||||||
|
QList<QUrl> fileUriList;
|
||||||
|
if (!fileContent.isEmpty()) {
|
||||||
|
if (mimeFormat.contains("image/")) {
|
||||||
|
QImage image;
|
||||||
|
image.loadFromData(fileContent, nullptr);
|
||||||
|
resultMimeData->setImageData(image);
|
||||||
|
} else {
|
||||||
|
QUrl fileUrl(QStringLiteral("file:///") +
|
||||||
|
QString::fromStdString(webfile.name()));
|
||||||
|
fileUriList.append(fileUrl);
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QFile::WriteOnly)) {
|
||||||
|
qWarning() << "File was not opened";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.write(fileContent) < 0)
|
||||||
|
qWarning() << "Write failed";
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
resultMimeData->setUrls(fileUriList);
|
||||||
|
}
|
||||||
|
callback(*resultMimeData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ItemKind::String:
|
case ItemKind::String:
|
||||||
@ -131,9 +169,15 @@ QMimeData *DataTransfer::toMimeDataWithFile()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} // end items
|
||||||
if (!uriList.isEmpty())
|
|
||||||
|
if (!uriList.isEmpty()) {
|
||||||
resultMimeData->setUrls(uriList);
|
resultMimeData->setUrls(uriList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultMimeData->formats().length() > 0)
|
||||||
|
callback(*resultMimeData);
|
||||||
|
|
||||||
return resultMimeData;
|
return resultMimeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,13 +15,14 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <QMimeData>
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace qstdweb {
|
namespace qstdweb {
|
||||||
struct CancellationFlag;
|
struct CancellationFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
class QMimeData;
|
|
||||||
class QPoint;
|
class QPoint;
|
||||||
class QRect;
|
class QRect;
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ struct DataTransfer
|
|||||||
DataTransfer &operator=(const DataTransfer &other);
|
DataTransfer &operator=(const DataTransfer &other);
|
||||||
DataTransfer &operator=(DataTransfer &&other);
|
DataTransfer &operator=(DataTransfer &&other);
|
||||||
|
|
||||||
QMimeData *toMimeDataWithFile() ;
|
QMimeData *toMimeDataWithFile(std::function<void(QMimeData &)> callback);
|
||||||
QMimeData *toMimeDataPreview();
|
QMimeData *toMimeDataPreview();
|
||||||
void setDragImage(emscripten::val element, const QPoint &hotspot);
|
void setDragImage(emscripten::val element, const QPoint &hotspot);
|
||||||
void setData(std::string format, std::string data);
|
void setData(std::string format, std::string data);
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <QtCore/qeventloop.h>
|
#include <QtCore/qeventloop.h>
|
||||||
#include <QtCore/qmimedata.h>
|
#include <QtCore/qmimedata.h>
|
||||||
#include <QtCore/qtimer.h>
|
#include <QtCore/qtimer.h>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -155,19 +156,28 @@ void QWasmDrag::onNativeDrop(DragEvent *event)
|
|||||||
? m_dragState->drag->supportedActions()
|
? m_dragState->drag->supportedActions()
|
||||||
: (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
|
: (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
|
||||||
| Qt::DropAction::LinkAction);
|
| Qt::DropAction::LinkAction);
|
||||||
|
Qt::MouseButton mouseButton = event->mouseButton;
|
||||||
|
QFlags<Qt::KeyboardModifier> modifiers = event->modifiers;
|
||||||
|
|
||||||
|
const auto pointerCallback = std::function([&, wasmWindow, pointInTargetWindowCoords,
|
||||||
|
actions, mouseButton, modifiers](QMimeData &data) {
|
||||||
|
if (data.formats().count() == 0)
|
||||||
|
return;
|
||||||
auto dropResponse = std::make_shared<QPlatformDropQtResponse>(true, Qt::DropAction::CopyAction);
|
auto dropResponse = std::make_shared<QPlatformDropQtResponse>(true, Qt::DropAction::CopyAction);
|
||||||
QMimeData *data = event->dataTransfer.toMimeDataWithFile();
|
|
||||||
*dropResponse = QWindowSystemInterface::handleDrop(event->targetWindow, data,
|
*dropResponse = QWindowSystemInterface::handleDrop(wasmWindow->window(), &data,
|
||||||
pointInTargetWindowCoords.toPoint(), actions,
|
pointInTargetWindowCoords.toPoint(), actions,
|
||||||
event->mouseButton, event->modifiers);
|
mouseButton, modifiers);
|
||||||
|
|
||||||
if (dropResponse->isAccepted()) {
|
if (dropResponse->isAccepted()) {
|
||||||
event->acceptDrop();
|
// event->acceptDrop(); // boom
|
||||||
event->dataTransfer.setDropAction(dropResponse->acceptedAction());
|
// event->dataTransfer.setDropAction(dropResponse->acceptedAction());
|
||||||
|
|
||||||
m_dragState->dropAction = dropResponse->acceptedAction();
|
m_dragState->dropAction = dropResponse->acceptedAction();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event->dataTransfer.toMimeDataWithFile(pointerCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmDrag::onNativeDragFinished(DragEvent *event)
|
void QWasmDrag::onNativeDragFinished(DragEvent *event)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user