diff --git a/src/resources/markdown_template.js b/src/resources/markdown_template.js index 53e34ccd..72323c94 100644 --- a/src/resources/markdown_template.js +++ b/src/resources/markdown_template.js @@ -1626,7 +1626,8 @@ var htmlToText = function(identifier, id, timeStamp, html) { }; var performSmartLivePreview = function(lang, text, hints, isRegex) { - if (previewDiv.style.display == 'none') { + if (previewDiv.style.display == 'none' + || document.getSelection().type == 'Range') { return; } diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 40f388b4..771d92fc 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -247,7 +247,10 @@ max_tag_label_length=10 max_num_of_tag_labels=3 ; 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 multiple_keyboard_layout=true @@ -467,8 +470,12 @@ ApplySnippet=S Export=O ; Toggle live preview LivePreview=I +; Expand or restore live preview area +ExpandLivePreview=U ; Focus edit area FocusEditArea=Y +; Parse HTML and paste +ParseAndPaste=P [external_editors] ; Define external editors which could be called to edit notes diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 6821f686..07e964ef 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -312,7 +312,7 @@ void VConfigManager::initialize() "max_num_of_tag_labels").toInt(); m_smartLivePreview = getConfigFromSettings("global", - "smart_live_preview").toBool(); + "smart_live_preview").toInt(); m_multipleKeyboardLayout = getConfigFromSettings("global", "multiple_keyboard_layout").toBool(); diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index e650fa0f..0422a361 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -60,6 +60,12 @@ enum class KeyMode Invalid }; +enum SmartLivePreview +{ + Disabled = 0, + EditorToWeb = 0x1, + WebToEditor = 0x2 +}; class VConfigManager : public QObject { @@ -547,7 +553,8 @@ public: QChar getVimLeaderKey() const; - bool getSmartLivePreview() const; + int getSmartLivePreview() const; + void setSmartLivePreview(int p_preview); bool getMultipleKeyboardLayout() const; @@ -989,7 +996,7 @@ private: QChar m_vimLeaderKey; // Smart live preview. - bool m_smartLivePreview; + int m_smartLivePreview; // Support multiple keyboard layout. bool m_multipleKeyboardLayout; @@ -2550,11 +2557,21 @@ inline QChar VConfigManager::getVimLeaderKey() const return m_vimLeaderKey; } -inline bool VConfigManager::getSmartLivePreview() const +inline int VConfigManager::getSmartLivePreview() const { 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 { return m_multipleKeyboardLayout; diff --git a/src/veditarea.cpp b/src/veditarea.cpp index 717a3363..b002d148 100644 --- a/src/veditarea.cpp +++ b/src/veditarea.cpp @@ -14,6 +14,8 @@ #include "vcaptain.h" #include "vfilelist.h" #include "vmathjaxpreviewhelper.h" +#include "vmdtab.h" +#include "vmdeditor.h" extern VConfigManager *g_config; @@ -954,6 +956,14 @@ void VEditArea::registerCaptainTargets() g_config->getCaptainShortcutKeySequence("LivePreview"), this, 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) @@ -1139,9 +1149,40 @@ bool VEditArea::toggleLivePreviewByCaptain(void *p_target, void *p_data) Q_UNUSED(p_data); VEditArea *obj = static_cast(p_target); - VEditTab *tab = obj->getCurrentTab(); + VMdTab *tab = dynamic_cast(obj->getCurrentTab()); 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(p_target); + + VMdTab *tab = dynamic_cast(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(p_target); + + const VMdTab *tab = dynamic_cast(obj->getCurrentTab()); + if (tab && tab->isEditMode()) { + VMdEditor *editor = tab->getEditor(); + editor->parseAndPaste(); } return true; diff --git a/src/veditarea.h b/src/veditarea.h index 15db55dc..157dd46a 100644 --- a/src/veditarea.h +++ b/src/veditarea.h @@ -234,6 +234,12 @@ private: // Toggle live preview. 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. int curWindowIndex; diff --git a/src/veditor.cpp b/src/veditor.cpp index f8fccf11..7670db6c 100644 --- a/src/veditor.cpp +++ b/src/veditor.cpp @@ -519,35 +519,43 @@ bool VEditor::findText(const QString &p_text, bool wrapped = false; QTextCursor retCursor; int matches = 0; - int start = p_forward ? cursor.position() + 1 : cursor.position(); - if (p_cursor) { - start = p_forward ? p_cursor->position() + 1 : p_cursor->position(); - } - + int start = p_cursor ? p_cursor->position() : cursor.position(); if (p_useLeftSideOfCursor) { --start; } + int skipPosition = start; - bool found = findTextHelper(p_text, p_options, p_forward, start, - wrapped, retCursor); - if (found) { - Q_ASSERT(!retCursor.isNull()); - if (wrapped) { - showWrapLabel(); - } + bool found = false; + while (true) { + found = findTextHelper(p_text, p_options, p_forward, start, wrapped, retCursor); + if (found) { + Q_ASSERT(!retCursor.isNull()); + if (wrapped) { + showWrapLabel(); + } - if (p_cursor) { - p_cursor->setPosition(retCursor.selectionStart(), p_moveMode); + if (p_forward && retCursor.selectionStart() == skipPosition) { + // 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 { - cursor.setPosition(retCursor.selectionStart(), p_moveMode); - setTextCursorW(cursor); + clearSearchedWordHighlight(); } - highlightSearchedWord(p_text, p_options); - highlightSearchedWordUnderCursor(retCursor); - matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size(); - } else { - clearSearchedWordHighlight(); + break; } if (matches == 0) { @@ -561,6 +569,18 @@ bool VEditor::findText(const QString &p_text, 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) { QList &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword]; diff --git a/src/veditor.h b/src/veditor.h index 2a2968d7..465dc727 100644 --- a/src/veditor.h +++ b/src/veditor.h @@ -83,6 +83,13 @@ public: QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor, 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, uint p_options, const QString &p_replaceText, diff --git a/src/vedittab.h b/src/vedittab.h index 2b7f59ab..f9db4cd1 100644 --- a/src/vedittab.h +++ b/src/vedittab.h @@ -119,10 +119,6 @@ public: // Fetch tab stat info. virtual VWordCountInfo fetchWordCountInfo(bool p_editMode) const; - virtual void toggleLivePreview() - { - } - public slots: // Enter edit mode virtual void editFile() = 0; diff --git a/src/vlivepreviewhelper.cpp b/src/vlivepreviewhelper.cpp index 240fc8a2..72c5ab7f 100644 --- a/src/vlivepreviewhelper.cpp +++ b/src/vlivepreviewhelper.cpp @@ -202,6 +202,7 @@ void VLivePreviewHelper::updateCodeBlocks(TimeStamp p_timeStamp, const QVector= cursorBlock) { if (lastIndex == idx && cached && !oldCache) { needUpdate = false; + m_curLivePreviewInfo.update(vcb); } m_cbIndex = idx; @@ -260,12 +261,16 @@ void VLivePreviewHelper::handleCursorPositionChanged() void VLivePreviewHelper::updateLivePreview() { if (m_cbIndex < 0) { + m_curLivePreviewInfo.clear(); return; } Q_ASSERT(!(m_cbIndex & ~INDEX_MASK)); const CodeBlockPreviewInfo &cb = m_codeBlocks[m_cbIndex]; const VCodeBlock &vcb = cb.codeBlock(); + + m_curLivePreviewInfo.update(vcb); + if (vcb.m_lang == "dot") { if (!m_graphvizHelper) { m_graphvizHelper = new VGraphvizHelper(this); @@ -530,7 +535,7 @@ void VLivePreviewHelper::performSmartLivePreview() { if (m_cbIndex < 0 || m_cbIndex >= m_codeBlocks.size() - || !g_config->getSmartLivePreview()) { + || !(g_config->getSmartLivePreview() & SmartLivePreview::EditorToWeb)) { return; } diff --git a/src/vlivepreviewhelper.h b/src/vlivepreviewhelper.h index 6c0cd76d..c6be2cf3 100644 --- a/src/vlivepreviewhelper.h +++ b/src/vlivepreviewhelper.h @@ -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. class VLivePreviewHelper : public QObject { @@ -109,6 +139,8 @@ public: bool isPreviewEnabled() const; + const LivePreviewInfo &getLivePreviewInfo() const; + public slots: void updateCodeBlocks(TimeStamp p_timeStamp, const QVector &p_codeBlocks); @@ -220,7 +252,6 @@ private: QString m_imageBackground; }; - void checkLang(const QString &p_lang, bool &p_livePreview, bool &p_inplacePreview) const; // Get image data for this code block for inplace preview. @@ -277,6 +308,8 @@ private: int m_lastCursorBlock; QTimer *m_livePreviewTimer; + + LivePreviewInfo m_curLivePreviewInfo; }; inline bool VLivePreviewHelper::isPreviewEnabled() const @@ -292,4 +325,9 @@ inline qreal VLivePreviewHelper::getScaleFactor(const CodeBlockPreviewInfo &p_cb return m_scaleFactor; } } + +inline const LivePreviewInfo &VLivePreviewHelper::getLivePreviewInfo() const +{ + return m_curLivePreviewInfo; +} #endif // VLIVEPREVIEWHELPER_H diff --git a/src/vmdeditor.cpp b/src/vmdeditor.cpp index d75e8f55..75135f3c 100644 --- a/src/vmdeditor.cpp +++ b/src/vmdeditor.cpp @@ -27,6 +27,7 @@ #include "utils/vclipboardutils.h" #include "vplantumlhelper.h" #include "vgraphvizhelper.h" +#include "vmdtab.h" extern VWebUtils *g_webUtils; @@ -382,19 +383,25 @@ void VMdEditor::contextMenuEvent(QContextMenuEvent *p_event) emit m_object->discardAndRead(); }); - QAction *toggleLivePreviewAct = new QAction(tr("Live Preview For Graphs"), menu.data()); - toggleLivePreviewAct->setToolTip(tr("Toggle live preview panel for graphs")); - VUtils::fixTextWithCaptainShortcut(toggleLivePreviewAct, "LivePreview"); - connect(toggleLivePreviewAct, &QAction::triggered, - this, [this]() { - m_editTab->toggleLivePreview(); - }); + VMdTab *mdtab = dynamic_cast(m_editTab); + if (mdtab) { + QAction *toggleLivePreviewAct = new QAction(tr("Live Preview For Graphs"), menu.data()); + toggleLivePreviewAct->setToolTip(tr("Toggle live preview panel for graphs")); + VUtils::fixTextWithCaptainShortcut(toggleLivePreviewAct, "LivePreview"); + connect(toggleLivePreviewAct, &QAction::triggered, + this, [this, mdtab]() { + mdtab->toggleLivePreview(); + }); - menu->insertAction(firstAct, toggleLivePreviewAct); - menu->insertAction(toggleLivePreviewAct, discardExitAct); - menu->insertAction(discardExitAct, saveExitAct); - - menu->insertSeparator(toggleLivePreviewAct); + menu->insertAction(firstAct, toggleLivePreviewAct); + menu->insertAction(toggleLivePreviewAct, discardExitAct); + menu->insertAction(discardExitAct, saveExitAct); + menu->insertSeparator(toggleLivePreviewAct); + } else { + menu->insertAction(firstAct, discardExitAct); + menu->insertAction(discardExitAct, saveExitAct); + menu->insertSeparator(discardExitAct); + } if (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 *papAct = new QAction(tr("Paste Parsed &Markdown Text"), p_menu); + VUtils::fixTextWithCaptainShortcut(papAct, "ParseAndPaste"); papAct->setToolTip(tr("Parse HTML to Markdown text and paste")); connect(papAct, &QAction::triggered, - this, [this]() { - QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); - QString html(mimeData->html()); - if (!html.isEmpty()) { - ++m_copyTimeStamp; - emit requestHtmlToText(html, 0, m_copyTimeStamp); - } - }); - + this, &VMdEditor::parseAndPaste); insertActionAfter(p_after, papAct, p_menu); return papAct; @@ -1824,3 +1823,20 @@ void VMdEditor::exportGraphAndCopy(const QString &p_lang, 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); + } +} diff --git a/src/vmdeditor.h b/src/vmdeditor.h index ba105bc3..9fada57b 100644 --- a/src/vmdeditor.h +++ b/src/vmdeditor.h @@ -88,6 +88,8 @@ public slots: void htmlToTextFinished(int p_id, int p_timeStamp, const QString &p_html); + void parseAndPaste(); + // Wrapper functions for QPlainTextEdit/QTextEdit. public: void setExtraSelectionsW(const QList &p_selections) Q_DECL_OVERRIDE diff --git a/src/vmdtab.cpp b/src/vmdtab.cpp index eeeda21d..78f3979e 100644 --- a/src/vmdtab.cpp +++ b/src/vmdtab.cpp @@ -65,6 +65,26 @@ VMdTab::VMdTab(VFile *p_file, VEditArea *p_editArea, 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) { showFileEditMode(); } else { @@ -396,6 +416,10 @@ void VMdTab::setupMarkdownViewer() this, &VMdTab::editFile); connect(m_webViewer, &VWebView::requestSavePage, 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); m_webViewer->setPage(page); @@ -1516,18 +1540,51 @@ void VMdTab::setCurrentMode(Mode p_mode) focusChild(); } -void VMdTab::toggleLivePreview() +bool VMdTab::toggleLivePreview() { + bool ret = false; + switch (m_mode) { case Mode::EditPreview: setCurrentMode(Mode::Edit); + ret = true; break; case Mode::Edit: setCurrentMode(Mode::EditPreview); + ret = true; break; default: 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; } diff --git a/src/vmdtab.h b/src/vmdtab.h index dd3cb7d3..cf2d8a67 100644 --- a/src/vmdtab.h +++ b/src/vmdtab.h @@ -95,7 +95,9 @@ public: VWordCountInfo fetchWordCountInfo(bool p_editMode) const Q_DECL_OVERRIDE; // Toggle live preview in edit mode. - void toggleLivePreview() Q_DECL_OVERRIDE; + bool toggleLivePreview(); + + bool expandRestorePreviewArea(); public slots: // Enter edit mode. @@ -148,6 +150,9 @@ private slots: // Handle save page request. void handleSavePageRequested(); + // Selection changed in web. + void handleWebSelectionChanged(); + private: enum TabReady { None = 0, ReadMode = 0x1, EditMode = 0x2 }; @@ -243,6 +248,8 @@ private: // Timer to write backup file when content has been changed. QTimer *m_backupTimer; + QTimer *m_livePreviewTimer; + bool m_backupFileChecked; // Used to scroll to the header of edit mode in read mode. diff --git a/src/vwebview.cpp b/src/vwebview.cpp index b13d75b3..367334a0 100644 --- a/src/vwebview.cpp +++ b/src/vwebview.cpp @@ -45,6 +45,9 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event) menu->setToolTipsVisible(true); const QList actions = menu->actions(); + QAction *firstAction = actions.isEmpty() ? NULL : actions[0]; + + bool selection = hasSelection(); #if defined(Q_OS_WIN) if (!m_copyImageUrlActionHooked) { @@ -64,26 +67,46 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event) } #endif - if (!hasSelection() - && !m_inPreview - && 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(actions.isEmpty() ? NULL : actions[0], editAct); - // actions does not contain editAction. - if (!actions.isEmpty()) { - menu->insertSeparator(actions[0]); + if (!selection) { + if (m_inPreview) { + QAction *expandAct = new QAction(tr("Expand/Restore Preview Area"), menu); + VUtils::fixTextWithCaptainShortcut(expandAct, "ExpandLivePreview"); + connect(expandAct, &QAction::triggered, + this, &VWebView::requestExpandRestorePreviewArea); + menu->insertAction(firstAction, expandAct); + + initPreviewTunnelMenu(firstAction, menu); + + if (firstAction) { + menu->insertSeparator(firstAction); + } + } 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. - QAction *copyAct = pageAction(QWebEnginePage::Copy); - if (actions.contains(copyAct) && !m_inPreview) { - initCopyAsMenu(copyAct, menu); + { + QAction *copyAct = pageAction(QWebEnginePage::Copy); + if (actions.contains(copyAct) && !m_inPreview) { + initCopyAsMenu(copyAct, menu); + } } // We need to replace the "Copy Image" action: @@ -100,13 +123,6 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event) 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. if (!m_inPreview) { initCopyAllAsMenu(menu); @@ -419,3 +435,49 @@ void VWebView::handleCopyAllAsAction(QAction *p_act) 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); +} diff --git a/src/vwebview.h b/src/vwebview.h index 039a7887..08988bc6 100644 --- a/src/vwebview.h +++ b/src/vwebview.h @@ -22,6 +22,8 @@ signals: void requestSavePage(); + void requestExpandRestorePreviewArea(); + protected: void contextMenuEvent(QContextMenuEvent *p_event); @@ -56,6 +58,8 @@ private: void initCopyAllAsMenu(QMenu *p_menu); + void initPreviewTunnelMenu(QAction *p_before, QMenu *p_menu); + VFile *m_file; // Whether this view has hooked the Copy Image Url action.