bug-fix: loop to setMimeData to clipboard in Windows

This commit is contained in:
Le Tan 2017-12-28 19:26:43 +08:00
parent bbfc12ab18
commit 00d7f5e013
3 changed files with 147 additions and 6 deletions

View File

@ -1,6 +1,7 @@
#include "vclipboardutils.h"
#include <QDebug>
#include <QMimeData>
#include "vutils.h"
@ -33,3 +34,132 @@ void VClipboardUtils::setImageLoop(QClipboard *p_clipboard,
VUtils::sleepWait(100 /* ms */);
}
}
void VClipboardUtils::setMimeDataToClipboard(QClipboard *p_clipboard,
QMimeData *p_mimeData,
QClipboard::Mode p_mode)
{
#if defined(Q_OS_WIN)
// On Windows, setMimeData() may fail. We will repeatedly retry until succeed.
setMimeDataLoop(p_clipboard, p_mimeData, p_mode);
#else
p_clipboard->setMimeData(p_mimeData, p_mode);
#endif
}
static QMimeData *cloneMimeData(const QMimeData *p_mimeData)
{
QMimeData *da = new QMimeData();
if (p_mimeData->hasUrls()) {
da->setUrls(p_mimeData->urls());
}
if (p_mimeData->hasText()) {
da->setText(p_mimeData->text());
}
if (p_mimeData->hasColor()) {
da->setColorData(p_mimeData->colorData());
}
if (p_mimeData->hasHtml()) {
da->setHtml(p_mimeData->html());
}
if (p_mimeData->hasImage()) {
da->setImageData(p_mimeData->imageData());
}
return da;
}
static bool mimeDataEquals(const QMimeData *p_a, const QMimeData *p_b)
{
if ((p_a && !p_b) || (!p_a && p_b)) {
return false;
}
if (p_a->hasUrls()) {
if (!p_b->hasUrls()) {
return false;
}
if (p_a->urls() != p_b->urls()) {
return false;
}
} else if (p_b->hasUrls()) {
return false;
}
if (p_a->hasText()) {
if (!p_b->hasText()) {
return false;
}
if (p_a->text() != p_b->text()) {
return false;
}
} else if (p_b->hasText()) {
return false;
}
if (p_a->hasColor()) {
if (!p_b->hasColor()) {
return false;
}
if (p_a->colorData() != p_b->colorData()) {
return false;
}
} else if (p_b->hasColor()) {
return false;
}
if (p_a->hasHtml()) {
if (!p_b->hasHtml()) {
return false;
}
if (p_a->html() != p_b->html()) {
return false;
}
} else if (p_b->hasHtml()) {
return false;
}
if (p_a->hasImage()) {
if (!p_b->hasImage()) {
return false;
}
if (p_a->imageData() != p_b->imageData()) {
return false;
}
} else if (p_b->hasImage()) {
return false;
}
return true;
}
void VClipboardUtils::setMimeDataLoop(QClipboard *p_clipboard,
QMimeData *p_mimeData,
QClipboard::Mode p_mode)
{
while (true) {
// Make a backup.
QMimeData *tmp = cloneMimeData(p_mimeData);
p_clipboard->setMimeData(p_mimeData, p_mode);
const QMimeData *out = p_clipboard->mimeData(p_mode);
if (mimeDataEquals(tmp, out)) {
delete tmp;
break;
}
qDebug() << "fail to set mimeData, retry";
p_mimeData = tmp;
VUtils::sleepWait(100 /* ms */);
}
}

View File

@ -4,6 +4,8 @@
#include <QImage>
#include <QClipboard>
class QMimeData;
class VClipboardUtils
{
@ -12,6 +14,10 @@ public:
const QImage &p_image,
QClipboard::Mode p_mode = QClipboard::Clipboard);
static void setMimeDataToClipboard(QClipboard *p_clipboard,
QMimeData *p_mimeData,
QClipboard::Mode p_mode = QClipboard::Clipboard);
private:
VClipboardUtils()
{
@ -20,6 +26,10 @@ private:
static void setImageLoop(QClipboard *p_clipboard,
const QImage &p_image,
QClipboard::Mode p_mode);
static void setMimeDataLoop(QClipboard *p_clipboard,
QMimeData *p_mimeData,
QClipboard::Mode p_mode);
};
#endif // VCLIPBOARDUTILS_H

View File

@ -108,7 +108,7 @@ void VWebView::copyImage()
QString imgPath;
if (mimeData->hasUrls()) {
QList<QUrl> urls = mimeData->urls();
if (urls[0].isLocalFile()) {
if (!urls.isEmpty() && urls[0].isLocalFile()) {
imgPath = urls[0].toLocalFile();
}
}
@ -149,7 +149,7 @@ void VWebView::handleCopyImageUrlAction()
QMimeData *data = new QMimeData();
data->setUrls(urls);
data->setText(spaceOnlyText);
clipboard->setMimeData(data);
VClipboardUtils::setMimeDataToClipboard(clipboard, data, QClipboard::Clipboard);
clipboard->setProperty(c_ClipboardPropertyMark.toLatin1(), true);
qDebug() << "clipboard copy image URL altered" << spaceOnlyText;
@ -160,15 +160,16 @@ void VWebView::handleCopyImageUrlAction()
void VWebView::hideUnusedActions(QMenu *p_menu)
{
const QList<QAction *> actions = p_menu->actions();
QList<QAction *> unusedActions;
// QWebEnginePage uses different actions of Back/Forward/Reload.
// [Woboq](https://code.woboq.org/qt5/qtwebengine/src/webenginewidgets/api/qwebenginepage.cpp.html#1652)
// We tell these three actions by name.
static const QStringList actionNames({QWebEnginePage::tr("&Back"), QWebEnginePage::tr("&Forward"), QWebEnginePage::tr("&Reload")});
const QStringList actionNames({QWebEnginePage::tr("&Back"),
QWebEnginePage::tr("&Forward"),
QWebEnginePage::tr("&Reload")});
const QList<QAction *> actions = p_menu->actions();
for (auto it : actions) {
if (actionNames.contains(it->text())) {
unusedActions.append(it);
@ -224,7 +225,7 @@ void VWebView::handleCopyAction()
data->setText(mimeData->text());
}
clipboard->setMimeData(data);
VClipboardUtils::setMimeDataToClipboard(clipboard, data, QClipboard::Clipboard);
clipboard->setProperty(c_ClipboardPropertyMark.toLatin1(), true);
qDebug() << "clipboard copy Html altered" << html;
}