summaryrefslogtreecommitdiffstats
path: root/tests/manual/wasm
diff options
context:
space:
mode:
authorLorn Potter <lorn.potter@gmail.com>2021-05-14 18:37:12 +1000
committerLorn Potter <lorn.potter@gmail.com>2021-12-08 13:39:58 +1000
commitf0be152896471aa392bb1b2b649b66feb31480cc (patch)
treeaa8a3d1c6776416c45578d75177c8eba05ee0f35 /tests/manual/wasm
parent3b24713098abd34cf8652da815f4dcf3a22110d3 (diff)
wasm: improve clipboard support
Add support for Clipboard API Add clipboard manual test Also includes these fixes: - improve clipboard use for chrome browser - make QClipboard::setText work - html copy and paste - image copy/paste Chrome browser supports text, html and png To use the Clipboard API, apps need to be served from a secure context (https). There is a fallback in the case of non secure context (http) - Firefox requires dom.events.asyncClipboard.read, dom.events.asyncClipboard.clipboardItem and dom.events.asyncClipboard.dataTransfer to be set from about:config, in order to support the Clipboard API. Change-Id: Ie4cb1bbb1dfc77e9655090a30967632780d15dd9 Fixes: QTBUG-74504 Fixes: QTBUG-93619 Fixes: QTBUG-79365 Fixes: QTBUG-86169 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Diffstat (limited to 'tests/manual/wasm')
-rw-r--r--tests/manual/wasm/CMakeLists.txt1
-rw-r--r--tests/manual/wasm/clipboard/CMakeLists.txt46
-rw-r--r--tests/manual/wasm/clipboard/README2
-rw-r--r--tests/manual/wasm/clipboard/clipboard.pro27
-rw-r--r--tests/manual/wasm/clipboard/data.qrc5
-rw-r--r--tests/manual/wasm/clipboard/data/qticon64.pngbin0 -> 6474 bytes
-rw-r--r--tests/manual/wasm/clipboard/main.cpp61
-rw-r--r--tests/manual/wasm/clipboard/mainwindow.cpp287
-rw-r--r--tests/manual/wasm/clipboard/mainwindow.h94
-rw-r--r--tests/manual/wasm/clipboard/mainwindow.ui222
10 files changed, 745 insertions, 0 deletions
diff --git a/tests/manual/wasm/CMakeLists.txt b/tests/manual/wasm/CMakeLists.txt
index cd594e7112..dd0d816a5d 100644
--- a/tests/manual/wasm/CMakeLists.txt
+++ b/tests/manual/wasm/CMakeLists.txt
@@ -2,4 +2,5 @@ add_subdirectory(eventloop)
if(QT_FEATURE_widgets)
add_subdirectory(cursors)
add_subdirectory(localfiles)
+add_subdirectory(clipboard)
endif()
diff --git a/tests/manual/wasm/clipboard/CMakeLists.txt b/tests/manual/wasm/clipboard/CMakeLists.txt
new file mode 100644
index 0000000000..4bc60a5edc
--- /dev/null
+++ b/tests/manual/wasm/clipboard/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Generated from clipboard.pro.
+
+#####################################################################
+## clipboard Binary:
+#####################################################################
+
+qt_internal_add_manual_test(clipboard
+ GUI
+ SOURCES
+ main.cpp
+ mainwindow.cpp mainwindow.h mainwindow.ui
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
+ ENABLE_AUTOGEN_TOOLS
+ uic
+)
+# Resources:
+set(data_resource_files
+ "data/qticon64.png"
+)
+
+qt_internal_add_resource(clipboard "data"
+ PREFIX
+ "/"
+ FILES
+ ${data_resource_files}
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(clipboard CONDITION (QT_MAJOR_VERSION GREATER 4)
+ PUBLIC_LIBRARIES
+ Qt::Widgets
+)
+
+#### Keys ignored in scope 3:.:.:clipboard.pro:QNX:
+# target.path = "/tmp/$${TARGET}/bin"
+
+#### Keys ignored in scope 5:.:.:clipboard.pro:UNIX AND NOT ANDROID:
+# target.path = "/opt/$${TARGET}/bin"
+
+#### Keys ignored in scope 6:.:.:clipboard.pro:NOT target.path_ISEMPTY:
+# INSTALLS = "target"
diff --git a/tests/manual/wasm/clipboard/README b/tests/manual/wasm/clipboard/README
new file mode 100644
index 0000000000..91529696ca
--- /dev/null
+++ b/tests/manual/wasm/clipboard/README
@@ -0,0 +1,2 @@
+The Clipboard manual test app can be used both on desktop and in the browser
+using WebAssembly to test clipboard use between WebAssembly app and the desktop.
diff --git a/tests/manual/wasm/clipboard/clipboard.pro b/tests/manual/wasm/clipboard/clipboard.pro
new file mode 100644
index 0000000000..3286049225
--- /dev/null
+++ b/tests/manual/wasm/clipboard/clipboard.pro
@@ -0,0 +1,27 @@
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+RESOURCES += \
+ data.qrc
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/tests/manual/wasm/clipboard/data.qrc b/tests/manual/wasm/clipboard/data.qrc
new file mode 100644
index 0000000000..c0f33f25be
--- /dev/null
+++ b/tests/manual/wasm/clipboard/data.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/qticon64.png</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/wasm/clipboard/data/qticon64.png b/tests/manual/wasm/clipboard/data/qticon64.png
new file mode 100644
index 0000000000..76f02c6c96
--- /dev/null
+++ b/tests/manual/wasm/clipboard/data/qticon64.png
Binary files differ
diff --git a/tests/manual/wasm/clipboard/main.cpp b/tests/manual/wasm/clipboard/main.cpp
new file mode 100644
index 0000000000..cdffd01766
--- /dev/null
+++ b/tests/manual/wasm/clipboard/main.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/manual/wasm/clipboard/mainwindow.cpp b/tests/manual/wasm/clipboard/mainwindow.cpp
new file mode 100644
index 0000000000..2b8a162c2d
--- /dev/null
+++ b/tests/manual/wasm/clipboard/mainwindow.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include <QClipboard>
+#include <QMimeData>
+#include <QImageReader>
+#include <QBuffer>
+#include <QRandomGenerator>
+#include <QPainter>
+#include <QKeyEvent>
+
+#ifdef Q_OS_WASM
+#include <emscripten.h>
+#include <emscripten/html5.h>
+#include <emscripten/val.h>
+#include <emscripten/bind.h>
+
+using namespace emscripten;
+#endif
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ ui->imageLabel->installEventFilter(this);
+
+ ui->imageLabel->setBackgroundRole(QPalette::Base);
+ ui->imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+ ui->imageLabel->setScaledContents(true);
+
+ clipboard = QGuiApplication::clipboard();
+ connect(
+ clipboard, &QClipboard::dataChanged,
+ [=]() {
+ ui->textEdit_2->insertHtml("<b>Clipboard data changed:</b><br>");
+ const QMimeData *mimeData = clipboard->mimeData();
+ QByteArray ba;
+
+ for (auto mimetype : mimeData->formats()) {
+ qDebug() << Q_FUNC_INFO << mimetype;
+ ba = mimeData->data(mimetype);
+ }
+ QString sizeStr;
+
+ if (mimeData->hasImage()) {
+ qsizetype imageSize = qvariant_cast<QImage>(mimeData->imageData()).sizeInBytes();
+ sizeStr.setNum(imageSize);
+ ui->textEdit_2->insertHtml("has Image data: " + sizeStr + "<br>");
+ }
+
+ if (mimeData->hasHtml()) {
+ int size = mimeData->html().length();
+ sizeStr.setNum(size);
+ ui->textEdit_2->insertHtml("has html data: " + sizeStr + "<br>");
+ }
+ if (mimeData->hasText()) {
+ int size = mimeData->text().length();
+ sizeStr.setNum(size);
+ ui->textEdit_2->insertHtml("has text data: " + sizeStr + "<br>");
+ }
+
+ ui->textEdit_2->insertHtml(mimeData->formats().join(" | ")+ "<br>");
+
+ ui->textEdit_2->ensureCursorVisible();
+
+ const QString message = tr("Clipboard changed, %1 ")
+ .arg(mimeData->formats().join(' '));
+
+ statusBar()->showMessage(message + sizeStr);
+ }
+ );
+#ifdef Q_OS_WASM
+ val clipboard = val::global("navigator")["clipboard"];
+ bool hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined());
+ QString messageApi;
+ if (hasClipboardApi)
+ messageApi = QStringLiteral("Using Clipboard API");
+ else
+ messageApi = QStringLiteral("Using Clipboard events");
+ ui->label->setText(messageApi);
+#else
+ ui->label->setText("desktop clipboard");
+#endif
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::on_setTextButton_clicked()
+{
+ QGuiApplication::clipboard()->setText(ui->textEdit->textCursor().selectedText());
+}
+
+static QImage clipboardImage()
+{
+ if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData()) {
+ if (mimeData->hasImage()) {
+ const QImage image = qvariant_cast<QImage>(mimeData->imageData());
+ if (!image.isNull())
+ return image;
+ }
+ }
+ return QImage();
+}
+
+static QByteArray clipboardBinary()
+{
+ if (const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData()) {
+
+ if (mimeData->formats().contains("application/octet-stream")) {
+ const QByteArray ba = qvariant_cast<QByteArray>(mimeData->data("application/octet-stream"));
+ qDebug() << Q_FUNC_INFO << ba;
+ if (!ba.isNull())
+ return ba;
+ }
+ }
+ return QByteArray();
+}
+
+void MainWindow::on_pasteImageButton_clicked()
+{
+ const QImage newImage = clipboardImage();
+ if (newImage.isNull()) {
+ qDebug() << "No image in clipboard";
+ const QString message = tr("No image in clipboard")
+ .arg(newImage.width()).arg(newImage.height()).arg(newImage.depth());
+ statusBar()->showMessage(message);
+ } else {
+ setImage(newImage);
+ setWindowFilePath(QString());
+ const QString message = tr("Obtained image from clipboard, %1x%2, Depth: %3")
+ .arg(newImage.width()).arg(newImage.height()).arg(newImage.depth());
+ statusBar()->showMessage(message);
+ }
+}
+
+void MainWindow::setImage(const QImage &newImage)
+{
+ image = newImage;
+ ui->imageLabel->setPixmap(QPixmap::fromImage(image));
+}
+
+void MainWindow::on_pasteTextButton_clicked()
+{
+ ui->textEdit->insertPlainText(QGuiApplication::clipboard()->text());
+}
+
+void MainWindow::on_copyBinaryButton_clicked()
+{
+ QByteArray ba;
+ ba.resize(10);
+ ba[0] = 0x3c;
+ ba[1] = 0xb8;
+ ba[2] = 0x64;
+ ba[3] = 0x18;
+ ba[4] = 0xca;
+ ba[5] = 0xca;
+ ba[6] = 0x18;
+ ba[7] = 0x64;
+ ba[8] = 0xb8;
+ ba[9] = 0x3c;
+
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setData("application/octet-stream", ba);
+ QGuiApplication::clipboard()->setMimeData(mimeData);
+
+ const QString message = tr("Copied binary to clipboard: " + ba + " 10 bytes");
+ statusBar()->showMessage(message);
+}
+
+void MainWindow::on_pasteBinaryButton_clicked()
+{
+ const QByteArray ba = clipboardBinary();
+ if (ba.isNull()) {
+ qDebug() << "No binary in clipboard";
+ const QString message = tr("No binary in clipboard");
+ statusBar()->showMessage(message);
+ } else {
+ setWindowFilePath(QString());
+ const QString message = tr("Obtained binary from clipboard: " + ba);
+ statusBar()->showMessage(message);
+ }
+}
+
+void MainWindow::on_comboBox_textActivated(const QString &arg1)
+{
+ QImage image(QSize(150,100), QImage::Format_RGB32);
+ QPainter painter(&image);
+ painter.fillRect(QRectF(0,0,150,100),generateRandomColor());
+ painter.fillRect(QRectF(20,30,130,40),generateRandomColor());
+ painter.setPen(QPen(generateRandomColor()));
+ painter.drawText(QRect(25,30,130,40),"Qt WebAssembly");
+
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ image.save(&buffer, arg1.toLocal8Bit());
+
+ qDebug() << ba.mid(0,10) << ba.length();
+ qDebug() << Q_FUNC_INFO << image.sizeInBytes();
+
+ QGuiApplication::clipboard()->setImage(image);
+}
+
+QColor MainWindow::generateRandomColor()
+{
+ return QColor::fromRgb(QRandomGenerator::global()->generate());
+}
+
+bool MainWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (ke->key() == Qt::Key_V && ke->modifiers().testFlag(Qt::ControlModifier)) {
+ if (obj == ui->imageLabel) {
+ setImage(clipboardImage());
+ return true;
+ }
+ }
+ }
+ // standard event processing
+ return QObject::eventFilter(obj, event);
+}
+
+void MainWindow::on_pasteHtmlButton_clicked()
+{
+ ui->textEdit->insertHtml(QGuiApplication::clipboard()->mimeData()->html());
+}
+
+void MainWindow::on_clearButton_clicked()
+{
+ ui->textEdit_2->clear();
+}
+
diff --git a/tests/manual/wasm/clipboard/mainwindow.h b/tests/manual/wasm/clipboard/mainwindow.h
new file mode 100644
index 0000000000..69e21ba8a2
--- /dev/null
+++ b/tests/manual/wasm/clipboard/mainwindow.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+private slots:
+ void on_setTextButton_clicked();
+
+ void on_pasteImageButton_clicked();
+ void setImage(const QImage &newImage);
+ void on_pasteTextButton_clicked();
+
+
+ void on_copyBinaryButton_clicked();
+
+ void on_pasteBinaryButton_clicked();
+
+ void on_comboBox_textActivated(const QString &arg1);
+
+ void on_pasteHtmlButton_clicked();
+
+ void on_clearButton_clicked();
+
+private:
+ Ui::MainWindow *ui;
+ QImage image;
+ QClipboard *clipboard;
+ bool eventFilter(QObject *obj, QEvent *event) override;
+
+ QColor generateRandomColor();
+};
+#endif // MAINWINDOW_H
diff --git a/tests/manual/wasm/clipboard/mainwindow.ui b/tests/manual/wasm/clipboard/mainwindow.ui
new file mode 100644
index 0000000000..84606598cc
--- /dev/null
+++ b/tests/manual/wasm/clipboard/mainwindow.ui
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1222</width>
+ <height>1011</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="setTextButton">
+ <property name="text">
+ <string>setText()</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pasteTextButton">
+ <property name="text">
+ <string>paste text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pasteHtmlButton">
+ <property name="text">
+ <string>paste html</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="comboBox">
+ <property name="currentText">
+ <string>PNG</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>PNG</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>JPG</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>BMP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>NAN</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pasteImageButton">
+ <property name="text">
+ <string>paste image</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="copyBinaryButton">
+ <property name="text">
+ <string>setData</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pasteBinaryButton">
+ <property name="text">
+ <string>paste data</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="clearButton">
+ <property name="text">
+ <string>clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="textEdit_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="0">
+ <widget class="QTextBrowser" name="textEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>400</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;img src=&quot;:/data/qticon64.png&quot; /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a name=&quot;tw-target&quot;&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'monospace'; font-weight:600;&quot;&gt;L&lt;/span&gt;&lt;span style=&quot; font-family:'monospace'; font-weight:600;&quot;&gt;orem&lt;/span&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt; &lt;/span&gt;&lt;span style=&quot; font-family:'monospace'; font-style:italic;&quot;&gt;ipsum&lt;/span&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt; &lt;/span&gt;&lt;span style=&quot; font-family:'monospace'; text-decoration: underline;&quot;&gt;dolor&lt;/span&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt; &lt;/span&gt;&lt;span style=&quot; font-family:'monospace'; vertical-align:super;&quot;&gt;sit&lt;/span&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt; &lt;/span&gt;&lt;span style=&quot; font-family:'monospace'; vertical-align:sub;&quot;&gt;amet&lt;/span&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://localhost&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;consectetur&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt; &lt;/span&gt;&lt;span style=&quot; font-family:'monospace'; color:#7320a4;&quot;&gt;adipiscing&lt;/span&gt;&lt;span style=&quot; font-family:'monospace';&quot;&gt; elit. Som medlemmer av byrået ønsker imidlertid en eiendomsmegler. Ullamcorper største lekseforfatter. Dolor et consectetuer litt ernæring. Maecenas smile jord sitter Vulputate medlemmer og, basketball ethvert problem. Reservert lever nå propaganda. På makroen investere laoreet kan, av enhver latter. Jasmine som en TV -tegneserie.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'monospace';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="imageLabel">
+ <property name="mouseTracking">
+ <bool>true</bool>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <property name="text">
+ <string>Paste image here</string>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1222</width>
+ <height>29</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>