MarkdownEditor: support RichPaste as default

This commit is contained in:
Le Tan 2022-03-30 21:19:14 +08:00
parent 5a8eb1e7aa
commit ecce8d13c1
8 changed files with 141 additions and 44 deletions

View File

@ -53,7 +53,7 @@ namespace vnotex
TypeTable,
TypeMark,
Outline,
RichPaste,
AltPaste,
FindAndReplace,
FindNext,
FindPrevious,

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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" : [

View File

@ -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;
}

View File

@ -88,6 +88,8 @@ namespace vnotex
QCheckBox *m_editorOverriddenFontFamilyCheckBox = nullptr;
QFontComboBox *m_editorOverriddenFontFamilyComboBox = nullptr;
QCheckBox *m_richPasteByDefaultCheckBox = nullptr;
};
}

View File

@ -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 <img>.
QRegExp reg("<img ([^>]*)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<QMenu> *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);
}
}

View File

@ -126,7 +126,7 @@ namespace vnotex
void handleContextMenuEvent(QContextMenuEvent *p_event, bool *p_handled, QScopedPointer<QMenu> *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;
};
}