refine context menu of VWebView

- Hide unused actions.
This commit is contained in:
Le Tan 2017-12-27 20:36:03 +08:00
parent 58b57c2a86
commit d193cd28a5
2 changed files with 158 additions and 47 deletions

View File

@ -19,60 +19,39 @@
static const QString c_ClipboardPropertyMark = "CopiedImageURLAltered"; static const QString c_ClipboardPropertyMark = "CopiedImageURLAltered";
VWebView::VWebView(VFile *p_file, QWidget *p_parent) VWebView::VWebView(VFile *p_file, QWidget *p_parent)
: QWebEngineView(p_parent), m_file(p_file), m_actionHooked(false) : QWebEngineView(p_parent),
m_file(p_file),
m_copyImageUrlActionHooked(false),
m_copyActionHooked(false)
{ {
setAcceptDrops(false); setAcceptDrops(false);
} }
void VWebView::contextMenuEvent(QContextMenuEvent *p_event) 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(); QMenu *menu = page()->createStandardContextMenu();
menu->setToolTipsVisible(true); menu->setToolTipsVisible(true);
const QList<QAction *> actions = menu->actions(); const QList<QAction *> actions = menu->actions();
#if defined(Q_OS_WIN)
if (!m_copyImageUrlActionHooked) {
// "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 = getPageAction(actions, QWebEnginePage::CopyImageUrlToClipboard);
if (actions.contains(copyImageUrlAct)) {
connect(copyImageUrlAct, &QAction::triggered,
this, &VWebView::handleCopyImageUrlAction);
m_copyImageUrlActionHooked = true;
qDebug() << "hooked CopyImageUrl action" << copyImageUrlAct;
}
}
#endif
if (!hasSelection() && m_file && m_file->isModifiable()) { if (!hasSelection() && m_file && m_file->isModifiable()) {
QAction *editAct= new QAction(VIconUtils::menuIcon(":/resources/icons/edit_note.svg"), QAction *editAct= new QAction(VIconUtils::menuIcon(":/resources/icons/edit_note.svg"),
tr("&Edit"), menu); tr("&Edit"), menu);
@ -90,17 +69,19 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
// the fully-encoded URL to fetch the image while Windows seems to not // the fully-encoded URL to fetch the image while Windows seems to not
// recognize it. // recognize it.
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
QAction *defaultCopyImageAct = pageAction(QWebEnginePage::CopyImageToClipboard); QAction *defaultCopyImageAct = getPageAction(actions, QWebEnginePage::CopyImageToClipboard);
if (defaultCopyImageAct && actions.contains(defaultCopyImageAct)) { if (defaultCopyImageAct && actions.contains(defaultCopyImageAct)) {
QAction *copyImageAct = new QAction(defaultCopyImageAct->text(), menu); QAction *copyImageAct = new QAction(defaultCopyImageAct->text(), menu);
copyImageAct->setToolTip(defaultCopyImageAct->toolTip()); copyImageAct->setToolTip(defaultCopyImageAct->toolTip());
connect(copyImageAct, &QAction::triggered, connect(copyImageAct, &QAction::triggered,
this, &VWebView::copyImage); this, &VWebView::copyImage);
menu->insertAction(defaultCopyImageAct, copyImageAct); menu->insertAction(defaultCopyImageAct, copyImageAct);
menu->removeAction(defaultCopyImageAct); defaultCopyImageAct->setVisible(false);
} }
#endif #endif
hideUnusedActions(menu);
menu->exec(p_event->globalPos()); menu->exec(p_event->globalPos());
delete menu; delete menu;
} }
@ -112,7 +93,7 @@ void VWebView::handleEditAction()
void VWebView::copyImage() void VWebView::copyImage()
{ {
Q_ASSERT(m_actionHooked); Q_ASSERT(m_copyImageUrlActionHooked);
// triggerPageAction(QWebEnginePage::CopyImageUrlToClipboard) will not really // triggerPageAction(QWebEnginePage::CopyImageUrlToClipboard) will not really
// trigger the corresponding action. It just do the stuff directly. // trigger the corresponding action. It just do the stuff directly.
@ -145,3 +126,120 @@ void VWebView::copyImage()
// Fall back. // Fall back.
triggerPageAction(QWebEnginePage::CopyImageToClipboard); triggerPageAction(QWebEnginePage::CopyImageToClipboard);
} }
void VWebView::handleCopyImageUrlAction()
{
// 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;
}
}
}
}
void VWebView::hideUnusedActions(QMenu *p_menu)
{
const QList<QAction *> actions = p_menu->actions();
QList<QAction *> unusedActions;
// Back.
QAction *act = getPageAction(actions, QWebEnginePage::Back);
unusedActions.append(act);
// Forward.
act = getPageAction(actions, QWebEnginePage::Forward);
unusedActions.append(act);
// Reload.
act = getPageAction(actions, QWebEnginePage::Reload);
unusedActions.append(act);
// ViewSource.
act = getPageAction(actions, QWebEnginePage::ViewSource);
unusedActions.append(act);
// DownloadImageToDisk.
act = getPageAction(actions, QWebEnginePage::DownloadImageToDisk);
unusedActions.append(act);
for (auto it : unusedActions) {
if (it) {
it->setVisible(false);
}
}
}
void VWebView::handleCopyAction()
{
// 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);
qDebug() << clipboard->ownsClipboard() << mimeData->hasHtml();
if (clipboard->ownsClipboard()
&& mimeData->hasHtml()) {
QString html = mimeData->html();
if (html.startsWith("<html>")) {
return;
}
html = QString("<html><body><!--StartFragment-->%1<!--EndFragment--></body></html>").arg(html);
// Set new mime data.
QMimeData *data = new QMimeData();
data->setHtml(html);
if (mimeData->hasUrls()) {
data->setUrls(mimeData->urls());
}
if (mimeData->hasText()) {
data->setText(mimeData->text());
}
clipboard->setMimeData(data);
clipboard->setProperty(c_ClipboardPropertyMark.toLatin1(), true);
qDebug() << "clipboard copy Html altered" << html;
}
}
QAction *VWebView::getPageAction(const QList<QAction *> &p_actions,
QWebEnginePage::WebAction p_webAction)
{
QAction *act = pageAction(p_webAction);
if (act && !p_actions.contains(act)) {
QString text = act->text();
for (auto it : p_actions) {
if (it->text().endsWith(text)) {
act = it;
break;
}
}
}
return act;
}

View File

@ -4,6 +4,7 @@
#include <QWebEngineView> #include <QWebEngineView>
class VFile; class VFile;
class QMenu;
class VWebView : public QWebEngineView class VWebView : public QWebEngineView
{ {
@ -21,15 +22,27 @@ protected:
private slots: private slots:
void handleEditAction(); void handleEditAction();
void handleCopyImageUrlAction();
void handleCopyAction();
// Copy the clicked image. // Copy the clicked image.
// Used to replace the default CopyImageToClipboard action. // Used to replace the default CopyImageToClipboard action.
void copyImage(); void copyImage();
private: private:
void hideUnusedActions(QMenu *p_menu);
// pageAction() may not return exactly the action in use.
QAction *getPageAction(const QList<QAction *> &p_actions,
QWebEnginePage::WebAction p_webAction);
VFile *m_file; VFile *m_file;
// Whether this view has hooked the Copy Image Url action. // Whether this view has hooked the Copy Image Url action.
bool m_actionHooked; bool m_copyImageUrlActionHooked;
bool m_copyActionHooked;
}; };
#endif // VWEBVIEW_H #endif // VWEBVIEW_H