Browse Source

bug-fix: copying image/imageURl in read mode fails due to URL encoding on Windows

Le Tan 8 years ago
parent
commit
33146efcd9
2 changed files with 110 additions and 2 deletions
  1. 103 2
      src/vwebview.cpp
  2. 7 0
      src/vwebview.h

+ 103 - 2
src/vwebview.cpp

@@ -6,15 +6,65 @@
 #include <QWebEnginePage>
 #include <QAction>
 #include <QList>
+#include <QClipboard>
+#include <QMimeData>
+#include <QApplication>
+#include <QImage>
 #include "vfile.h"
 
+// We set the property of the clipboard to mark that the URL copied in the
+// clipboard has been altered.
+static const QString c_ClipboardPropertyMark = "CopiedImageURLAltered";
+
 VWebView::VWebView(VFile *p_file, QWidget *p_parent)
-    : QWebEngineView(p_parent), m_file(p_file)
+    : QWebEngineView(p_parent), m_file(p_file), m_actionHooked(false)
 {
 }
 
 void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
 {
+#if defined(Q_OS_WIN)
+    if (!m_actionHooked) {
+        m_actionHooked = true;
+
+        // "Copy Image URL" action will put the encoded URL to the clipboard as text
+        // and the URL as URLs. If the URL contains Chinese, OneNote or Word could not
+        // recognize it.
+        // We need to change it to only-space-encoded text.
+        QAction *copyImageUrlAct = pageAction(QWebEnginePage::CopyImageUrlToClipboard);
+        connect(copyImageUrlAct, &QAction::triggered,
+                this, [this](){
+                    // To avoid failure of setting clipboard mime data.
+                    QCoreApplication::processEvents();
+
+                    QClipboard *clipboard = QApplication::clipboard();
+                    const QMimeData *mimeData = clipboard->mimeData();
+                    clipboard->setProperty(c_ClipboardPropertyMark.toLatin1(), false);
+                    if (clipboard->ownsClipboard()
+                        && mimeData->hasText()
+                        && mimeData->hasUrls()) {
+                        QString text = mimeData->text();
+                        QList<QUrl> urls = mimeData->urls();
+                        if (urls.size() == 1
+                            && urls[0].isLocalFile()
+                            && urls[0].toEncoded() == text) {
+                            QString spaceOnlyText = urls[0].toString(QUrl::EncodeSpaces);
+                            if (spaceOnlyText != text) {
+                                // Set new mime data.
+                                QMimeData *data = new QMimeData();
+                                data->setUrls(urls);
+                                data->setText(spaceOnlyText);
+                                clipboard->setMimeData(data);
+
+                                clipboard->setProperty(c_ClipboardPropertyMark.toLatin1(), true);
+                                qDebug() << "clipboard copy image URL altered" << spaceOnlyText;
+                            }
+                        }
+                    }
+                });
+    }
+#endif
+
     QMenu *menu = page()->createStandardContextMenu();
     menu->setToolTipsVisible(true);
 
@@ -22,7 +72,7 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
 
     if (!hasSelection() && m_file && m_file->isModifiable()) {
         QAction *editAct= new QAction(QIcon(":/resources/icons/edit_note.svg"),
-                                          tr("&Edit"), this);
+                                      tr("&Edit"), menu);
         editAct->setToolTip(tr("Edit current note"));
         connect(editAct, &QAction::triggered,
                 this, &VWebView::handleEditAction);
@@ -33,6 +83,21 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
         }
     }
 
+    // We need to replace the "Copy Image" action, because the default one use
+    // the fully-encoded URL to fetch the image while Windows seems to not
+    // recognize it.
+#if defined(Q_OS_WIN)
+    QAction *defaultCopyImageAct = pageAction(QWebEnginePage::CopyImageToClipboard);
+    if (defaultCopyImageAct && actions.contains(defaultCopyImageAct)) {
+        QAction *copyImageAct = new QAction(defaultCopyImageAct->text(), menu);
+        copyImageAct->setToolTip(defaultCopyImageAct->toolTip());
+        connect(copyImageAct, &QAction::triggered,
+                this, &VWebView::copyImage);
+        menu->insertAction(defaultCopyImageAct, copyImageAct);
+        menu->removeAction(defaultCopyImageAct);
+    }
+#endif
+
     menu->exec(p_event->globalPos());
     delete menu;
 }
@@ -41,3 +106,39 @@ void VWebView::handleEditAction()
 {
     emit editNote();
 }
+
+void VWebView::copyImage()
+{
+    Q_ASSERT(m_actionHooked);
+
+    // triggerPageAction(QWebEnginePage::CopyImageUrlToClipboard) will not really
+    // trigger the corresponding action. It just do the stuff directly.
+    QAction *copyImageUrlAct = pageAction(QWebEnginePage::CopyImageUrlToClipboard);
+    copyImageUrlAct->trigger();
+
+    QCoreApplication::processEvents();
+
+    QClipboard *clipboard = QApplication::clipboard();
+    if (clipboard->property(c_ClipboardPropertyMark.toLatin1()).toBool()) {
+        const QMimeData *mimeData = clipboard->mimeData();
+        QString imgPath;
+        if (mimeData->hasUrls()) {
+            QList<QUrl> urls = mimeData->urls();
+            if (urls[0].isLocalFile()) {
+                imgPath = urls[0].toLocalFile();
+            }
+        }
+
+        if (!imgPath.isEmpty()) {
+            QImage img(imgPath);
+            if (!img.isNull()) {
+                clipboard->setImage(img, QClipboard::Clipboard);
+                qDebug() << "clipboard copy image via URL" << imgPath;
+                return;
+            }
+        }
+    }
+
+    // Fall back.
+    triggerPageAction(QWebEnginePage::CopyImageToClipboard);
+}

+ 7 - 0
src/vwebview.h

@@ -21,8 +21,15 @@ protected:
 private slots:
     void handleEditAction();
 
+    // Copy the clicked image.
+    // Used to replace the default CopyImageToClipboard action.
+    void copyImage();
+
 private:
     VFile *m_file;
+
+    // Whether this view has hooked the Copy Image Url action.
+    bool m_actionHooked;
 };
 
 #endif // VWEBVIEW_H