LivePreview: support bidirectional smart live preview

This commit is contained in:
Le Tan 2018-09-05 20:16:05 +08:00
parent 2338002b1f
commit 060c02297b
17 changed files with 368 additions and 82 deletions

View File

@ -1626,7 +1626,8 @@ var htmlToText = function(identifier, id, timeStamp, html) {
}; };
var performSmartLivePreview = function(lang, text, hints, isRegex) { var performSmartLivePreview = function(lang, text, hints, isRegex) {
if (previewDiv.style.display == 'none') { if (previewDiv.style.display == 'none'
|| document.getSelection().type == 'Range') {
return; return;
} }

View File

@ -247,7 +247,10 @@ max_tag_label_length=10
max_num_of_tag_labels=3 max_num_of_tag_labels=3
; Smart live preview ; Smart live preview
smart_live_preview=true ; 0 - disable smart live preview
; 1 - editor to web
; 2 - web to editor
smart_live_preview=3
; Support multiple keyboard layout ; Support multiple keyboard layout
multiple_keyboard_layout=true multiple_keyboard_layout=true
@ -467,8 +470,12 @@ ApplySnippet=S
Export=O Export=O
; Toggle live preview ; Toggle live preview
LivePreview=I LivePreview=I
; Expand or restore live preview area
ExpandLivePreview=U
; Focus edit area ; Focus edit area
FocusEditArea=Y FocusEditArea=Y
; Parse HTML and paste
ParseAndPaste=P
[external_editors] [external_editors]
; Define external editors which could be called to edit notes ; Define external editors which could be called to edit notes

View File

@ -312,7 +312,7 @@ void VConfigManager::initialize()
"max_num_of_tag_labels").toInt(); "max_num_of_tag_labels").toInt();
m_smartLivePreview = getConfigFromSettings("global", m_smartLivePreview = getConfigFromSettings("global",
"smart_live_preview").toBool(); "smart_live_preview").toInt();
m_multipleKeyboardLayout = getConfigFromSettings("global", m_multipleKeyboardLayout = getConfigFromSettings("global",
"multiple_keyboard_layout").toBool(); "multiple_keyboard_layout").toBool();

View File

@ -60,6 +60,12 @@ enum class KeyMode
Invalid Invalid
}; };
enum SmartLivePreview
{
Disabled = 0,
EditorToWeb = 0x1,
WebToEditor = 0x2
};
class VConfigManager : public QObject class VConfigManager : public QObject
{ {
@ -547,7 +553,8 @@ public:
QChar getVimLeaderKey() const; QChar getVimLeaderKey() const;
bool getSmartLivePreview() const; int getSmartLivePreview() const;
void setSmartLivePreview(int p_preview);
bool getMultipleKeyboardLayout() const; bool getMultipleKeyboardLayout() const;
@ -989,7 +996,7 @@ private:
QChar m_vimLeaderKey; QChar m_vimLeaderKey;
// Smart live preview. // Smart live preview.
bool m_smartLivePreview; int m_smartLivePreview;
// Support multiple keyboard layout. // Support multiple keyboard layout.
bool m_multipleKeyboardLayout; bool m_multipleKeyboardLayout;
@ -2550,11 +2557,21 @@ inline QChar VConfigManager::getVimLeaderKey() const
return m_vimLeaderKey; return m_vimLeaderKey;
} }
inline bool VConfigManager::getSmartLivePreview() const inline int VConfigManager::getSmartLivePreview() const
{ {
return m_smartLivePreview; return m_smartLivePreview;
} }
inline void VConfigManager::setSmartLivePreview(int p_preview)
{
if (m_smartLivePreview == p_preview) {
return;
}
m_smartLivePreview = p_preview;
setConfigToSettings("global", "smart_live_preview", m_smartLivePreview);
}
inline bool VConfigManager::getMultipleKeyboardLayout() const inline bool VConfigManager::getMultipleKeyboardLayout() const
{ {
return m_multipleKeyboardLayout; return m_multipleKeyboardLayout;

View File

@ -14,6 +14,8 @@
#include "vcaptain.h" #include "vcaptain.h"
#include "vfilelist.h" #include "vfilelist.h"
#include "vmathjaxpreviewhelper.h" #include "vmathjaxpreviewhelper.h"
#include "vmdtab.h"
#include "vmdeditor.h"
extern VConfigManager *g_config; extern VConfigManager *g_config;
@ -954,6 +956,14 @@ void VEditArea::registerCaptainTargets()
g_config->getCaptainShortcutKeySequence("LivePreview"), g_config->getCaptainShortcutKeySequence("LivePreview"),
this, this,
toggleLivePreviewByCaptain); toggleLivePreviewByCaptain);
captain->registerCaptainTarget(tr("ExpandLivePreview"),
g_config->getCaptainShortcutKeySequence("ExpandLivePreview"),
this,
expandLivePreviewByCaptain);
captain->registerCaptainTarget(tr("ParseAndPaste"),
g_config->getCaptainShortcutKeySequence("ParseAndPaste"),
this,
parseAndPasteByCaptain);
} }
bool VEditArea::activateTabByCaptain(void *p_target, void *p_data, int p_idx) bool VEditArea::activateTabByCaptain(void *p_target, void *p_data, int p_idx)
@ -1139,9 +1149,40 @@ bool VEditArea::toggleLivePreviewByCaptain(void *p_target, void *p_data)
Q_UNUSED(p_data); Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target); VEditArea *obj = static_cast<VEditArea *>(p_target);
VEditTab *tab = obj->getCurrentTab(); VMdTab *tab = dynamic_cast<VMdTab *>(obj->getCurrentTab());
if (tab) { if (tab) {
tab->toggleLivePreview(); if (tab->toggleLivePreview()) {
return false;
}
}
return true;
}
bool VEditArea::expandLivePreviewByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
VMdTab *tab = dynamic_cast<VMdTab *>(obj->getCurrentTab());
if (tab) {
if (tab->expandRestorePreviewArea()) {
return false;
}
}
return true;
}
bool VEditArea::parseAndPasteByCaptain(void *p_target, void *p_data)
{
Q_UNUSED(p_data);
VEditArea *obj = static_cast<VEditArea *>(p_target);
const VMdTab *tab = dynamic_cast<const VMdTab *>(obj->getCurrentTab());
if (tab && tab->isEditMode()) {
VMdEditor *editor = tab->getEditor();
editor->parseAndPaste();
} }
return true; return true;

View File

@ -234,6 +234,12 @@ private:
// Toggle live preview. // Toggle live preview.
static bool toggleLivePreviewByCaptain(void *p_target, void *p_data); static bool toggleLivePreviewByCaptain(void *p_target, void *p_data);
// Expand live preview.
static bool expandLivePreviewByCaptain(void *p_target, void *p_data);
// Parse and paste.
static bool parseAndPasteByCaptain(void *p_target, void *p_data);
// End Captain mode functions. // End Captain mode functions.
int curWindowIndex; int curWindowIndex;

View File

@ -519,35 +519,43 @@ bool VEditor::findText(const QString &p_text,
bool wrapped = false; bool wrapped = false;
QTextCursor retCursor; QTextCursor retCursor;
int matches = 0; int matches = 0;
int start = p_forward ? cursor.position() + 1 : cursor.position(); int start = p_cursor ? p_cursor->position() : cursor.position();
if (p_cursor) {
start = p_forward ? p_cursor->position() + 1 : p_cursor->position();
}
if (p_useLeftSideOfCursor) { if (p_useLeftSideOfCursor) {
--start; --start;
} }
int skipPosition = start;
bool found = findTextHelper(p_text, p_options, p_forward, start, bool found = false;
wrapped, retCursor); while (true) {
if (found) { found = findTextHelper(p_text, p_options, p_forward, start, wrapped, retCursor);
Q_ASSERT(!retCursor.isNull()); if (found) {
if (wrapped) { Q_ASSERT(!retCursor.isNull());
showWrapLabel(); if (wrapped) {
} showWrapLabel();
}
if (p_cursor) { if (p_forward && retCursor.selectionStart() == skipPosition) {
p_cursor->setPosition(retCursor.selectionStart(), p_moveMode); // Skip the first match.
skipPosition = -1;
start = retCursor.selectionEnd();
continue;
}
if (p_cursor) {
p_cursor->setPosition(retCursor.selectionStart(), p_moveMode);
} else {
cursor.setPosition(retCursor.selectionStart(), p_moveMode);
setTextCursorW(cursor);
}
highlightSearchedWord(p_text, p_options);
highlightSearchedWordUnderCursor(retCursor);
matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size();
} else { } else {
cursor.setPosition(retCursor.selectionStart(), p_moveMode); clearSearchedWordHighlight();
setTextCursorW(cursor);
} }
highlightSearchedWord(p_text, p_options); break;
highlightSearchedWordUnderCursor(retCursor);
matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size();
} else {
clearSearchedWordHighlight();
} }
if (matches == 0) { if (matches == 0) {
@ -561,6 +569,18 @@ bool VEditor::findText(const QString &p_text,
return found; return found;
} }
bool VEditor::findTextInRange(const QString &p_text,
uint p_options,
bool p_forward,
int p_start,
int p_end)
{
Q_UNUSED(p_start);
Q_UNUSED(p_end);
// TODO
return findText(p_text, p_options, p_forward);
}
void VEditor::highlightIncrementalSearchedWord(const QTextCursor &p_cursor) void VEditor::highlightIncrementalSearchedWord(const QTextCursor &p_cursor)
{ {
QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword]; QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword];

View File

@ -83,6 +83,13 @@ public:
QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor, QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor,
bool p_useLeftSideOfCursor = false); bool p_useLeftSideOfCursor = false);
// Constrain the scope.
bool findTextInRange(const QString &p_text,
uint p_options,
bool p_forward,
int p_start,
int p_end);
void replaceText(const QString &p_text, void replaceText(const QString &p_text,
uint p_options, uint p_options,
const QString &p_replaceText, const QString &p_replaceText,

View File

@ -119,10 +119,6 @@ public:
// Fetch tab stat info. // Fetch tab stat info.
virtual VWordCountInfo fetchWordCountInfo(bool p_editMode) const; virtual VWordCountInfo fetchWordCountInfo(bool p_editMode) const;
virtual void toggleLivePreview()
{
}
public slots: public slots:
// Enter edit mode // Enter edit mode
virtual void editFile() = 0; virtual void editFile() = 0;

View File

@ -202,6 +202,7 @@ void VLivePreviewHelper::updateCodeBlocks(TimeStamp p_timeStamp, const QVector<V
&& vcb.m_endBlock >= cursorBlock) { && vcb.m_endBlock >= cursorBlock) {
if (lastIndex == idx && cached && !oldCache) { if (lastIndex == idx && cached && !oldCache) {
needUpdate = false; needUpdate = false;
m_curLivePreviewInfo.update(vcb);
} }
m_cbIndex = idx; m_cbIndex = idx;
@ -260,12 +261,16 @@ void VLivePreviewHelper::handleCursorPositionChanged()
void VLivePreviewHelper::updateLivePreview() void VLivePreviewHelper::updateLivePreview()
{ {
if (m_cbIndex < 0) { if (m_cbIndex < 0) {
m_curLivePreviewInfo.clear();
return; return;
} }
Q_ASSERT(!(m_cbIndex & ~INDEX_MASK)); Q_ASSERT(!(m_cbIndex & ~INDEX_MASK));
const CodeBlockPreviewInfo &cb = m_codeBlocks[m_cbIndex]; const CodeBlockPreviewInfo &cb = m_codeBlocks[m_cbIndex];
const VCodeBlock &vcb = cb.codeBlock(); const VCodeBlock &vcb = cb.codeBlock();
m_curLivePreviewInfo.update(vcb);
if (vcb.m_lang == "dot") { if (vcb.m_lang == "dot") {
if (!m_graphvizHelper) { if (!m_graphvizHelper) {
m_graphvizHelper = new VGraphvizHelper(this); m_graphvizHelper = new VGraphvizHelper(this);
@ -530,7 +535,7 @@ void VLivePreviewHelper::performSmartLivePreview()
{ {
if (m_cbIndex < 0 if (m_cbIndex < 0
|| m_cbIndex >= m_codeBlocks.size() || m_cbIndex >= m_codeBlocks.size()
|| !g_config->getSmartLivePreview()) { || !(g_config->getSmartLivePreview() & SmartLivePreview::EditorToWeb)) {
return; return;
} }

View File

@ -92,6 +92,36 @@ private:
}; };
struct LivePreviewInfo
{
LivePreviewInfo()
: m_startPos(),
m_endPos()
{
}
void clear()
{
m_startPos = 0;
m_endPos = 0;
}
void update(const VCodeBlock &p_cb)
{
m_startPos = p_cb.m_startPos;
m_endPos = p_cb.m_startPos + p_cb.m_text.size();
}
bool isValid() const
{
return m_endPos > m_startPos;
}
int m_startPos;
int m_endPos;
};
// Manage live preview and inplace preview. // Manage live preview and inplace preview.
class VLivePreviewHelper : public QObject class VLivePreviewHelper : public QObject
{ {
@ -109,6 +139,8 @@ public:
bool isPreviewEnabled() const; bool isPreviewEnabled() const;
const LivePreviewInfo &getLivePreviewInfo() const;
public slots: public slots:
void updateCodeBlocks(TimeStamp p_timeStamp, const QVector<VCodeBlock> &p_codeBlocks); void updateCodeBlocks(TimeStamp p_timeStamp, const QVector<VCodeBlock> &p_codeBlocks);
@ -220,7 +252,6 @@ private:
QString m_imageBackground; QString m_imageBackground;
}; };
void checkLang(const QString &p_lang, bool &p_livePreview, bool &p_inplacePreview) const; void checkLang(const QString &p_lang, bool &p_livePreview, bool &p_inplacePreview) const;
// Get image data for this code block for inplace preview. // Get image data for this code block for inplace preview.
@ -277,6 +308,8 @@ private:
int m_lastCursorBlock; int m_lastCursorBlock;
QTimer *m_livePreviewTimer; QTimer *m_livePreviewTimer;
LivePreviewInfo m_curLivePreviewInfo;
}; };
inline bool VLivePreviewHelper::isPreviewEnabled() const inline bool VLivePreviewHelper::isPreviewEnabled() const
@ -292,4 +325,9 @@ inline qreal VLivePreviewHelper::getScaleFactor(const CodeBlockPreviewInfo &p_cb
return m_scaleFactor; return m_scaleFactor;
} }
} }
inline const LivePreviewInfo &VLivePreviewHelper::getLivePreviewInfo() const
{
return m_curLivePreviewInfo;
}
#endif // VLIVEPREVIEWHELPER_H #endif // VLIVEPREVIEWHELPER_H

View File

@ -27,6 +27,7 @@
#include "utils/vclipboardutils.h" #include "utils/vclipboardutils.h"
#include "vplantumlhelper.h" #include "vplantumlhelper.h"
#include "vgraphvizhelper.h" #include "vgraphvizhelper.h"
#include "vmdtab.h"
extern VWebUtils *g_webUtils; extern VWebUtils *g_webUtils;
@ -382,19 +383,25 @@ void VMdEditor::contextMenuEvent(QContextMenuEvent *p_event)
emit m_object->discardAndRead(); emit m_object->discardAndRead();
}); });
QAction *toggleLivePreviewAct = new QAction(tr("Live Preview For Graphs"), menu.data()); VMdTab *mdtab = dynamic_cast<VMdTab *>(m_editTab);
toggleLivePreviewAct->setToolTip(tr("Toggle live preview panel for graphs")); if (mdtab) {
VUtils::fixTextWithCaptainShortcut(toggleLivePreviewAct, "LivePreview"); QAction *toggleLivePreviewAct = new QAction(tr("Live Preview For Graphs"), menu.data());
connect(toggleLivePreviewAct, &QAction::triggered, toggleLivePreviewAct->setToolTip(tr("Toggle live preview panel for graphs"));
this, [this]() { VUtils::fixTextWithCaptainShortcut(toggleLivePreviewAct, "LivePreview");
m_editTab->toggleLivePreview(); connect(toggleLivePreviewAct, &QAction::triggered,
}); this, [this, mdtab]() {
mdtab->toggleLivePreview();
});
menu->insertAction(firstAct, toggleLivePreviewAct); menu->insertAction(firstAct, toggleLivePreviewAct);
menu->insertAction(toggleLivePreviewAct, discardExitAct); menu->insertAction(toggleLivePreviewAct, discardExitAct);
menu->insertAction(discardExitAct, saveExitAct); menu->insertAction(discardExitAct, saveExitAct);
menu->insertSeparator(toggleLivePreviewAct);
menu->insertSeparator(toggleLivePreviewAct); } else {
menu->insertAction(firstAct, discardExitAct);
menu->insertAction(discardExitAct, saveExitAct);
menu->insertSeparator(discardExitAct);
}
if (firstAct) { if (firstAct) {
menu->insertSeparator(firstAct); menu->insertSeparator(firstAct);
@ -1389,18 +1396,10 @@ QAction *VMdEditor::initPasteAsBlockQuoteMenu(QAction *p_after, QMenu *p_menu)
QAction *VMdEditor::initPasteAfterParseMenu(QAction *p_after, QMenu *p_menu) QAction *VMdEditor::initPasteAfterParseMenu(QAction *p_after, QMenu *p_menu)
{ {
QAction *papAct = new QAction(tr("Paste Parsed &Markdown Text"), p_menu); QAction *papAct = new QAction(tr("Paste Parsed &Markdown Text"), p_menu);
VUtils::fixTextWithCaptainShortcut(papAct, "ParseAndPaste");
papAct->setToolTip(tr("Parse HTML to Markdown text and paste")); papAct->setToolTip(tr("Parse HTML to Markdown text and paste"));
connect(papAct, &QAction::triggered, connect(papAct, &QAction::triggered,
this, [this]() { this, &VMdEditor::parseAndPaste);
QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
QString html(mimeData->html());
if (!html.isEmpty()) {
++m_copyTimeStamp;
emit requestHtmlToText(html, 0, m_copyTimeStamp);
}
});
insertActionAfter(p_after, papAct, p_menu); insertActionAfter(p_after, papAct, p_menu);
return papAct; return papAct;
@ -1824,3 +1823,20 @@ void VMdEditor::exportGraphAndCopy(const QString &p_lang,
m_exportTempFile->close(); m_exportTempFile->close();
} }
void VMdEditor::parseAndPaste()
{
if (!m_editTab
|| !m_editTab->isEditMode()
|| isReadOnly()) {
return;
}
QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
QString html(mimeData->html());
if (!html.isEmpty()) {
++m_copyTimeStamp;
emit requestHtmlToText(html, 0, m_copyTimeStamp);
}
}

View File

@ -88,6 +88,8 @@ public slots:
void htmlToTextFinished(int p_id, int p_timeStamp, const QString &p_html); void htmlToTextFinished(int p_id, int p_timeStamp, const QString &p_html);
void parseAndPaste();
// Wrapper functions for QPlainTextEdit/QTextEdit. // Wrapper functions for QPlainTextEdit/QTextEdit.
public: public:
void setExtraSelectionsW(const QList<QTextEdit::ExtraSelection> &p_selections) Q_DECL_OVERRIDE void setExtraSelectionsW(const QList<QTextEdit::ExtraSelection> &p_selections) Q_DECL_OVERRIDE

View File

@ -65,6 +65,26 @@ VMdTab::VMdTab(VFile *p_file, VEditArea *p_editArea,
writeBackupFile(); writeBackupFile();
}); });
m_livePreviewTimer = new QTimer(this);
m_livePreviewTimer->setSingleShot(true);
m_livePreviewTimer->setInterval(500);
connect(m_livePreviewTimer, &QTimer::timeout,
this, [this]() {
QString text = m_webViewer->selectedText();
if (text.isEmpty()) {
return;
}
const LivePreviewInfo &info = m_livePreviewHelper->getLivePreviewInfo();
if (info.isValid()) {
m_editor->findTextInRange(text,
FindOption::CaseSensitive,
true,
info.m_startPos,
info.m_endPos);
}
});
if (p_mode == OpenFileMode::Edit) { if (p_mode == OpenFileMode::Edit) {
showFileEditMode(); showFileEditMode();
} else { } else {
@ -396,6 +416,10 @@ void VMdTab::setupMarkdownViewer()
this, &VMdTab::editFile); this, &VMdTab::editFile);
connect(m_webViewer, &VWebView::requestSavePage, connect(m_webViewer, &VWebView::requestSavePage,
this, &VMdTab::handleSavePageRequested); this, &VMdTab::handleSavePageRequested);
connect(m_webViewer, &VWebView::selectionChanged,
this, &VMdTab::handleWebSelectionChanged);
connect(m_webViewer, &VWebView::requestExpandRestorePreviewArea,
this, &VMdTab::expandRestorePreviewArea);
VPreviewPage *page = new VPreviewPage(m_webViewer); VPreviewPage *page = new VPreviewPage(m_webViewer);
m_webViewer->setPage(page); m_webViewer->setPage(page);
@ -1516,18 +1540,51 @@ void VMdTab::setCurrentMode(Mode p_mode)
focusChild(); focusChild();
} }
void VMdTab::toggleLivePreview() bool VMdTab::toggleLivePreview()
{ {
bool ret = false;
switch (m_mode) { switch (m_mode) {
case Mode::EditPreview: case Mode::EditPreview:
setCurrentMode(Mode::Edit); setCurrentMode(Mode::Edit);
ret = true;
break; break;
case Mode::Edit: case Mode::Edit:
setCurrentMode(Mode::EditPreview); setCurrentMode(Mode::EditPreview);
ret = true;
break; break;
default: default:
break; break;
} }
return ret;
}
void VMdTab::handleWebSelectionChanged()
{
if (m_mode != Mode::EditPreview
|| !(g_config->getSmartLivePreview() & SmartLivePreview::WebToEditor)) {
return;
}
m_livePreviewTimer->start();
}
bool VMdTab::expandRestorePreviewArea()
{
if (m_mode != Mode::EditPreview) {
return false;
}
if (m_editor->isVisible()) {
m_editor->hide();
m_webViewer->setFocus();
} else {
m_editor->show();
m_editor->setFocus();
}
return true;
} }

View File

@ -95,7 +95,9 @@ public:
VWordCountInfo fetchWordCountInfo(bool p_editMode) const Q_DECL_OVERRIDE; VWordCountInfo fetchWordCountInfo(bool p_editMode) const Q_DECL_OVERRIDE;
// Toggle live preview in edit mode. // Toggle live preview in edit mode.
void toggleLivePreview() Q_DECL_OVERRIDE; bool toggleLivePreview();
bool expandRestorePreviewArea();
public slots: public slots:
// Enter edit mode. // Enter edit mode.
@ -148,6 +150,9 @@ private slots:
// Handle save page request. // Handle save page request.
void handleSavePageRequested(); void handleSavePageRequested();
// Selection changed in web.
void handleWebSelectionChanged();
private: private:
enum TabReady { None = 0, ReadMode = 0x1, EditMode = 0x2 }; enum TabReady { None = 0, ReadMode = 0x1, EditMode = 0x2 };
@ -243,6 +248,8 @@ private:
// Timer to write backup file when content has been changed. // Timer to write backup file when content has been changed.
QTimer *m_backupTimer; QTimer *m_backupTimer;
QTimer *m_livePreviewTimer;
bool m_backupFileChecked; bool m_backupFileChecked;
// Used to scroll to the header of edit mode in read mode. // Used to scroll to the header of edit mode in read mode.

View File

@ -45,6 +45,9 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
menu->setToolTipsVisible(true); menu->setToolTipsVisible(true);
const QList<QAction *> actions = menu->actions(); const QList<QAction *> actions = menu->actions();
QAction *firstAction = actions.isEmpty() ? NULL : actions[0];
bool selection = hasSelection();
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
if (!m_copyImageUrlActionHooked) { if (!m_copyImageUrlActionHooked) {
@ -64,26 +67,46 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
} }
#endif #endif
if (!hasSelection() if (!selection) {
&& !m_inPreview if (m_inPreview) {
&& m_file QAction *expandAct = new QAction(tr("Expand/Restore Preview Area"), menu);
&& m_file->isModifiable()) { VUtils::fixTextWithCaptainShortcut(expandAct, "ExpandLivePreview");
QAction *editAct= new QAction(VIconUtils::menuIcon(":/resources/icons/edit_note.svg"), connect(expandAct, &QAction::triggered,
tr("&Edit"), menu); this, &VWebView::requestExpandRestorePreviewArea);
editAct->setToolTip(tr("Edit current note")); menu->insertAction(firstAction, expandAct);
connect(editAct, &QAction::triggered,
this, &VWebView::handleEditAction); initPreviewTunnelMenu(firstAction, menu);
menu->insertAction(actions.isEmpty() ? NULL : actions[0], editAct);
// actions does not contain editAction. if (firstAction) {
if (!actions.isEmpty()) { menu->insertSeparator(firstAction);
menu->insertSeparator(actions[0]); }
} else {
if (m_file && m_file->isModifiable()) {
QAction *editAct= new QAction(VIconUtils::menuIcon(":/resources/icons/edit_note.svg"),
tr("&Edit"),
menu);
editAct->setToolTip(tr("Edit current note"));
connect(editAct, &QAction::triggered,
this, &VWebView::handleEditAction);
menu->insertAction(firstAction, editAct);
if (firstAction) {
menu->insertSeparator(firstAction);
}
}
QAction *savePageAct = new QAction(QWebEnginePage::tr("Save &Page"), menu);
connect(savePageAct, &QAction::triggered,
this, &VWebView::requestSavePage);
menu->addAction(savePageAct);
} }
} }
// Add Copy As menu. // Add Copy As menu.
QAction *copyAct = pageAction(QWebEnginePage::Copy); {
if (actions.contains(copyAct) && !m_inPreview) { QAction *copyAct = pageAction(QWebEnginePage::Copy);
initCopyAsMenu(copyAct, menu); if (actions.contains(copyAct) && !m_inPreview) {
initCopyAsMenu(copyAct, menu);
}
} }
// We need to replace the "Copy Image" action: // We need to replace the "Copy Image" action:
@ -100,13 +123,6 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
defaultCopyImageAct->setVisible(false); defaultCopyImageAct->setVisible(false);
} }
if (!hasSelection() && !m_inPreview) {
QAction *savePageAct = new QAction(QWebEnginePage::tr("Save &Page"), menu);
connect(savePageAct, &QAction::triggered,
this, &VWebView::requestSavePage);
menu->addAction(savePageAct);
}
// Add Copy All As menu. // Add Copy All As menu.
if (!m_inPreview) { if (!m_inPreview) {
initCopyAllAsMenu(menu); initCopyAllAsMenu(menu);
@ -419,3 +435,49 @@ void VWebView::handleCopyAllAsAction(QAction *p_act)
triggerPageAction(QWebEnginePage::Unselect); triggerPageAction(QWebEnginePage::Unselect);
} }
void VWebView::initPreviewTunnelMenu(QAction *p_before, QMenu *p_menu)
{
QMenu *subMenu = new QMenu(tr("Live Preview Tunnel"), p_menu);
int config = g_config->getSmartLivePreview();
QActionGroup *ag = new QActionGroup(subMenu);
QAction *act = ag->addAction(tr("Disabled"));
act->setData(SmartLivePreview::Disabled);
act->setCheckable(true);
if (act->data().toInt() == config) {
act->setChecked(true);
}
act = ag->addAction(tr("Editor -> Preview"));
act->setData(SmartLivePreview::EditorToWeb);
act->setCheckable(true);
if (act->data().toInt() == config) {
act->setChecked(true);
}
act = ag->addAction(tr("Preview -> Editor"));
act->setData(SmartLivePreview::WebToEditor);
act->setCheckable(true);
if (act->data().toInt() == config) {
act->setChecked(true);
}
act = ag->addAction(tr("Bidirectional"));
act->setData(SmartLivePreview::EditorToWeb | SmartLivePreview::WebToEditor);
act->setCheckable(true);
if (act->data().toInt() == config) {
act->setChecked(true);
}
connect(ag, &QActionGroup::triggered,
this, [this](QAction *p_act) {
int data = p_act->data().toInt();
g_config->setSmartLivePreview(data);
});
subMenu->addActions(ag->actions());
p_menu->insertMenu(p_before, subMenu);
}

View File

@ -22,6 +22,8 @@ signals:
void requestSavePage(); void requestSavePage();
void requestExpandRestorePreviewArea();
protected: protected:
void contextMenuEvent(QContextMenuEvent *p_event); void contextMenuEvent(QContextMenuEvent *p_event);
@ -56,6 +58,8 @@ private:
void initCopyAllAsMenu(QMenu *p_menu); void initCopyAllAsMenu(QMenu *p_menu);
void initPreviewTunnelMenu(QAction *p_before, QMenu *p_menu);
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.