From ecce8d13c1d16f4dcc2ca53fcbda82a21957a04d Mon Sep 17 00:00:00 2001 From: Le Tan Date: Wed, 30 Mar 2022 21:19:14 +0800 Subject: [PATCH] MarkdownEditor: support RichPaste as default --- src/core/editorconfig.h | 2 +- src/core/markdowneditorconfig.cpp | 14 ++ src/core/markdowneditorconfig.h | 5 + src/data/core/vnotex.json | 5 +- .../dialogs/settings/markdowneditorpage.cpp | 14 ++ .../dialogs/settings/markdowneditorpage.h | 2 + src/widgets/editors/markdowneditor.cpp | 135 ++++++++++++------ src/widgets/editors/markdowneditor.h | 8 +- 8 files changed, 141 insertions(+), 44 deletions(-) diff --git a/src/core/editorconfig.h b/src/core/editorconfig.h index 405377a0..a81a79ac 100644 --- a/src/core/editorconfig.h +++ b/src/core/editorconfig.h @@ -53,7 +53,7 @@ namespace vnotex TypeTable, TypeMark, Outline, - RichPaste, + AltPaste, FindAndReplace, FindNext, FindPrevious, diff --git a/src/core/markdowneditorconfig.cpp b/src/core/markdowneditorconfig.cpp index c1091da4..7fd26cc8 100644 --- a/src/core/markdowneditorconfig.cpp +++ b/src/core/markdowneditorconfig.cpp @@ -78,6 +78,8 @@ void MarkdownEditorConfig::init(const QJsonObject &p_app, const QJsonObject &p_u } m_editViewMode = stringToEditViewMode(READSTR(QStringLiteral("edit_view_mode"))); + + m_richPasteByDefaultEnabled = READBOOL(QStringLiteral("rich_paste_by_default")); } QJsonObject MarkdownEditorConfig::toJson() const @@ -131,6 +133,8 @@ QJsonObject MarkdownEditorConfig::toJson() const obj[QStringLiteral("edit_view_mode")] = editViewModeToString(m_editViewMode); + obj[QStringLiteral("rich_paste_by_default")] = m_richPasteByDefaultEnabled; + return obj; } @@ -579,3 +583,13 @@ void MarkdownEditorConfig::setEditViewMode(EditViewMode p_mode) { updateConfig(m_editViewMode, p_mode, this); } + +bool MarkdownEditorConfig::getRichPasteByDefaultEnabled() const +{ + return m_richPasteByDefaultEnabled; +} + +void MarkdownEditorConfig::setRichPasteByDefaultEnabled(bool p_enabled) +{ + updateConfig(m_richPasteByDefaultEnabled, p_enabled, this); +} diff --git a/src/core/markdowneditorconfig.h b/src/core/markdowneditorconfig.h index d45deb67..9cbead37 100644 --- a/src/core/markdowneditorconfig.h +++ b/src/core/markdowneditorconfig.h @@ -145,6 +145,9 @@ namespace vnotex EditViewMode getEditViewMode() const; void setEditViewMode(EditViewMode p_mode); + bool getRichPasteByDefaultEnabled() const; + void setRichPasteByDefaultEnabled(bool p_enabled); + private: friend class MainConfig; @@ -254,6 +257,8 @@ namespace vnotex // View mode in edit mode. EditViewMode m_editViewMode = EditViewMode::EditOnly; + + bool m_richPasteByDefaultEnabled = true; }; } diff --git a/src/data/core/vnotex.json b/src/data/core/vnotex.json index c64006ca..41cfe8f9 100644 --- a/src/data/core/vnotex.json +++ b/src/data/core/vnotex.json @@ -201,7 +201,7 @@ "TypeTable" : "Ctrl+/", "TypeMark" : "Ctrl+G, M", "Outline" : "Ctrl+G, O", - "RichPaste" : "Ctrl+Shift+V", + "AltPaste" : "Ctrl+Shift+V", "FindAndReplace" : "Ctrl+F", "FindNext" : "F3", "FindPrevious" : "Shift+F3", @@ -451,7 +451,8 @@ "//comment" : "imagelink/codeblock/math", "inplace_preview_sources" : "imagelink;codeblock;math", "//comment" : "view mode of edit mode: editonly/editpreview", - "edit_view_mode" : "editonly" + "edit_view_mode" : "editonly", + "rich_paste_by_default" : true }, "image_host" : { "hosts" : [ diff --git a/src/widgets/dialogs/settings/markdowneditorpage.cpp b/src/widgets/dialogs/settings/markdowneditorpage.cpp index d1226b4a..53dd596d 100644 --- a/src/widgets/dialogs/settings/markdowneditorpage.cpp +++ b/src/widgets/dialogs/settings/markdowneditorpage.cpp @@ -122,6 +122,8 @@ void MarkdownEditorPage::loadInternal() m_editorOverriddenFontFamilyComboBox->setCurrentFont(font); } } + + m_richPasteByDefaultCheckBox->setChecked(markdownConfig.getRichPasteByDefaultEnabled()); } bool MarkdownEditorPage::saveInternal() @@ -198,6 +200,8 @@ bool MarkdownEditorPage::saveInternal() markdownConfig.setEditorOverriddenFontFamily(checked ? m_editorOverriddenFontFamilyComboBox->currentFont().family() : QString()); } + markdownConfig.setRichPasteByDefaultEnabled(m_richPasteByDefaultCheckBox->isChecked()); + EditorPage::notifyEditorConfigChange(); return true; @@ -402,6 +406,16 @@ QGroupBox *MarkdownEditorPage::setupEditGroup() layout->addRow(fontLayout); } + { + const QString label(tr("Use Rich Paste by default")); + m_richPasteByDefaultCheckBox = WidgetsFactory::createCheckBox(label, box); + m_richPasteByDefaultCheckBox->setToolTip(tr("Use Rich Paste by default when pasting text")); + layout->addRow(m_richPasteByDefaultCheckBox); + addSearchItem(label, m_richPasteByDefaultCheckBox->toolTip(), m_richPasteByDefaultCheckBox); + connect(m_richPasteByDefaultCheckBox, &QCheckBox::stateChanged, + this, &MarkdownEditorPage::pageIsChanged); + } + return box; } diff --git a/src/widgets/dialogs/settings/markdowneditorpage.h b/src/widgets/dialogs/settings/markdowneditorpage.h index 148b296e..4b689523 100644 --- a/src/widgets/dialogs/settings/markdowneditorpage.h +++ b/src/widgets/dialogs/settings/markdowneditorpage.h @@ -88,6 +88,8 @@ namespace vnotex QCheckBox *m_editorOverriddenFontFamilyCheckBox = nullptr; QFontComboBox *m_editorOverriddenFontFamilyComboBox = nullptr; + + QCheckBox *m_richPasteByDefaultCheckBox = nullptr; }; } diff --git a/src/widgets/editors/markdowneditor.cpp b/src/widgets/editors/markdowneditor.cpp index 1a753b5c..aa8094f1 100644 --- a/src/widgets/editors/markdowneditor.cpp +++ b/src/widgets/editors/markdowneditor.cpp @@ -62,9 +62,6 @@ using namespace vnotex; -// We set the property of the clipboard to mark that we are requesting a rich paste. -static const char *c_clipboardPropertyMark = "RichPaste"; - MarkdownEditor::Heading::Heading(const QString &p_name, int p_level, const QString &p_sectionNumber, @@ -468,32 +465,56 @@ void MarkdownEditor::insertImageLink(const QString &p_title, void MarkdownEditor::handleCanInsertFromMimeData(const QMimeData *p_source, bool *p_handled, bool *p_allowed) { - if (p_source->hasImage() || p_source->hasUrls()) { - if (p_source->hasImage() - || (!p_source->hasText() && !p_source->hasHtml()) - || QGuiApplication::keyboardModifiers() == Qt::ShiftModifier) { - // Change to Rich Paste. - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setProperty(c_clipboardPropertyMark, true); - } + m_shouldTriggerRichPaste = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig().getRichPasteByDefaultEnabled(); + + if (m_plainTextPasteAsked) { + m_shouldTriggerRichPaste = false; + return; + } + + if (m_richPasteAsked) { + m_shouldTriggerRichPaste = true; *p_handled = true; *p_allowed = true; + return; + } + + if (QGuiApplication::keyboardModifiers() == Qt::ShiftModifier) { + m_shouldTriggerRichPaste = !m_shouldTriggerRichPaste; + } + + if (m_shouldTriggerRichPaste) { + *p_handled = true; + *p_allowed = true; + return; + } + + if (p_source->hasImage()) { + m_shouldTriggerRichPaste = true; + *p_handled = true; + *p_allowed = true; + return; + } + + if (p_source->hasUrls()) { + *p_handled = true; + *p_allowed = true; + return; } } void MarkdownEditor::handleInsertFromMimeData(const QMimeData *p_source, bool *p_handled) { - QClipboard *clipboard = QApplication::clipboard(); - if (!clipboard->property(c_clipboardPropertyMark).toBool()) { + if (!m_shouldTriggerRichPaste) { // Default paste. - // Give tips about the Rich Paste and Parse As Markdown And Paste features. + // Give tips about the Rich Paste and Parse to Markdown And Paste features. VNoteX::getInst().showStatusMessageShort( tr("For advanced paste, try the \"Rich Paste\" and \"Parse to Markdown and Paste\" on the editor's context menu")); return; - } else { - clipboard->setProperty(c_clipboardPropertyMark, false); } + m_shouldTriggerRichPaste = false; + if (processHtmlFromMimeData(p_source)) { *p_handled = true; return; @@ -516,9 +537,10 @@ bool MarkdownEditor::processHtmlFromMimeData(const QMimeData *p_source) return false; } + const QString html(p_source->html()); + // Process . QRegExp reg("]*)src=\"([^\"]+)\"([^>]*)>"); - const QString html(p_source->html()); if (reg.indexIn(html) != -1 && HtmlUtils::hasOnlyImgTag(html)) { if (p_source->hasImage()) { // Both image data and URL are embedded. @@ -548,6 +570,24 @@ bool MarkdownEditor::processHtmlFromMimeData(const QMimeData *p_source) return true; } + // Parse to Markdown and Paste. + SelectDialog dialog(tr("Insert From Clipboard"), this); + dialog.addSelection(tr("Insert As Text"), 0); + dialog.addSelection(tr("Parse to Markdown and Paste"), 1); + + if (dialog.exec() == QDialog::Accepted) { + int selection = dialog.getSelection(); + if (selection == 0) { + // Insert as text. + m_textEdit->insertFromMimeDataOfBase(p_source); + return true; + } else if (selection == 1) { + // Parse to Markdown and Paste. + parseToMarkdownAndPaste(); + return true; + } + } + return false; } @@ -957,6 +997,8 @@ void MarkdownEditor::scrollToHeading(int p_idx) void MarkdownEditor::handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_handled, QScopedPointer *p_menu) { + const auto &editorConfig = ConfigMgr::getInst().getEditorConfig(); + *p_handled = true; p_menu->reset(m_textEdit->createStandardContextMenu(p_event->pos())); auto menu = p_menu->data(); @@ -970,8 +1012,7 @@ void MarkdownEditor::handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_ if (!hasSelection) { auto readAct = new QAction(tr("&Read"), menu); - WidgetUtils::addActionShortcutText(readAct, - ConfigMgr::getInst().getEditorConfig().getShortcut(EditorConfig::Shortcut::EditRead)); + WidgetUtils::addActionShortcutText(readAct, editorConfig.getShortcut(EditorConfig::Shortcut::EditRead)); connect(readAct, &QAction::triggered, this, &MarkdownEditor::readRequested); menu->insertAction(firstAct, readAct); @@ -986,20 +1027,21 @@ void MarkdownEditor::handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_ QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); - // Rich Paste. - auto richPasteAct = new QAction(tr("Rich Paste"), menu); - WidgetUtils::addActionShortcutText(richPasteAct, - ConfigMgr::getInst().getEditorConfig().getShortcut(EditorConfig::Shortcut::RichPaste)); - connect(richPasteAct, &QAction::triggered, - this, &MarkdownEditor::richPaste); - WidgetUtils::insertActionAfter(menu, pasteAct, richPasteAct); + // Rich Paste or Plain Text Paste. + const bool richPasteByDefault = editorConfig.getMarkdownEditorConfig().getRichPasteByDefaultEnabled(); + auto altPasteAct = new QAction(richPasteByDefault ? tr("Paste as Plain Text") : tr("Rich Paste"), menu); + WidgetUtils::addActionShortcutText(altPasteAct, + editorConfig.getShortcut(EditorConfig::Shortcut::AltPaste)); + connect(altPasteAct, &QAction::triggered, + this, &MarkdownEditor::altPaste); + WidgetUtils::insertActionAfter(menu, pasteAct, altPasteAct); if (mimeData->hasHtml()) { // Parse to Markdown and Paste. auto parsePasteAct = new QAction(tr("Parse to Markdown and Paste"), menu); connect(parsePasteAct, &QAction::triggered, this, &MarkdownEditor::parseToMarkdownAndPaste); - WidgetUtils::insertActionAfter(menu, richPasteAct, parsePasteAct); + WidgetUtils::insertActionAfter(menu, altPasteAct, parsePasteAct); } } @@ -1008,7 +1050,7 @@ void MarkdownEditor::handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_ auto snippetAct = menu->addAction(tr("Insert Snippet"), this, &MarkdownEditor::applySnippetRequested); WidgetUtils::addActionShortcutText(snippetAct, - ConfigMgr::getInst().getEditorConfig().getShortcut(EditorConfig::Shortcut::ApplySnippet)); + editorConfig.getShortcut(EditorConfig::Shortcut::ApplySnippet)); } if (!hasSelection) { @@ -1018,25 +1060,38 @@ void MarkdownEditor::handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_ appendSpellCheckMenu(p_event, menu); } -void MarkdownEditor::richPaste() +void MarkdownEditor::altPaste() { - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setProperty(c_clipboardPropertyMark, true); - m_textEdit->paste(); - clipboard->setProperty(c_clipboardPropertyMark, false); + const bool richPasteByDefault = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig().getRichPasteByDefaultEnabled(); + + if (richPasteByDefault) { + // Paste as plain text. + m_plainTextPasteAsked = true; + m_richPasteAsked = false; + } else { + // Rich paste. + m_plainTextPasteAsked = false; + m_richPasteAsked = true; + } + + // handleCanInsertFromMimeData() is called before this function. Call it manually. + if (m_textEdit->canPaste()) { + m_textEdit->paste(); + } + + m_plainTextPasteAsked = false; + m_richPasteAsked = false; } void MarkdownEditor::setupShortcuts() { const auto &editorConfig = ConfigMgr::getInst().getEditorConfig(); - { - auto shortcut = WidgetUtils::createShortcut(editorConfig.getShortcut(EditorConfig::Shortcut::RichPaste), - this); - if (shortcut) { - connect(shortcut, &QShortcut::activated, - this, &MarkdownEditor::richPaste); - } + auto shortcut = WidgetUtils::createShortcut(editorConfig.getShortcut(EditorConfig::Shortcut::AltPaste), + this); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, &MarkdownEditor::altPaste); } } diff --git a/src/widgets/editors/markdowneditor.h b/src/widgets/editors/markdowneditor.h index 848cb20a..631d2bde 100644 --- a/src/widgets/editors/markdowneditor.h +++ b/src/widgets/editors/markdowneditor.h @@ -126,7 +126,7 @@ namespace vnotex void handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_handled, QScopedPointer *p_menu); - void richPaste(); + void altPaste(); void parseToMarkdownAndPaste(); @@ -225,6 +225,12 @@ namespace vnotex MarkdownTableHelper *m_tableHelper = nullptr; ImageHost *m_imageHost = nullptr; + + bool m_shouldTriggerRichPaste = false; + + bool m_richPasteAsked = false; + + bool m_plainTextPasteAsked = false; }; }