mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support Insert Link tool bar button
Support Ctrl+L to insert a link.
This commit is contained in:
parent
da027e9fd9
commit
e66b70b6ff
132
src/dialog/vinsertlinkdialog.cpp
Normal file
132
src/dialog/vinsertlinkdialog.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
#include "vinsertlinkdialog.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "vlineedit.h"
|
||||
|
||||
VInsertLinkDialog::VInsertLinkDialog(const QString &p_title,
|
||||
const QString &p_text,
|
||||
const QString &p_info,
|
||||
const QString &p_linkText,
|
||||
const QString &p_linkUrl,
|
||||
QWidget *p_parent)
|
||||
: QDialog(p_parent)
|
||||
{
|
||||
setupUI(p_title, p_text, p_info, p_linkText, p_linkUrl);
|
||||
|
||||
fetchLinkFromClipboard();
|
||||
|
||||
handleInputChanged();
|
||||
}
|
||||
|
||||
void VInsertLinkDialog::setupUI(const QString &p_title,
|
||||
const QString &p_text,
|
||||
const QString &p_info,
|
||||
const QString &p_linkText,
|
||||
const QString &p_linkUrl)
|
||||
{
|
||||
QLabel *textLabel = NULL;
|
||||
if (!p_text.isEmpty()) {
|
||||
textLabel = new QLabel(p_text);
|
||||
textLabel->setWordWrap(true);
|
||||
}
|
||||
|
||||
QLabel *infoLabel = NULL;
|
||||
if (!p_info.isEmpty()) {
|
||||
infoLabel = new QLabel(p_info);
|
||||
infoLabel->setWordWrap(true);
|
||||
}
|
||||
|
||||
m_linkTextEdit = new VLineEdit(p_linkText);
|
||||
m_linkTextEdit->selectAll();
|
||||
|
||||
m_linkUrlEdit = new QLineEdit(p_linkUrl);
|
||||
m_linkUrlEdit->setToolTip(tr("Absolute or relative path of the link"));
|
||||
|
||||
QFormLayout *inputLayout = new QFormLayout();
|
||||
inputLayout->addRow(tr("&Text:"), m_linkTextEdit);
|
||||
inputLayout->addRow(tr("&URL:"), m_linkUrlEdit);
|
||||
|
||||
// Ok is the default button.
|
||||
m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
|
||||
m_linkTextEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
if (textLabel) {
|
||||
mainLayout->addWidget(textLabel);
|
||||
}
|
||||
|
||||
if (infoLabel) {
|
||||
mainLayout->addWidget(infoLabel);
|
||||
}
|
||||
|
||||
mainLayout->addLayout(inputLayout);
|
||||
mainLayout->addWidget(m_btnBox);
|
||||
|
||||
setLayout(mainLayout);
|
||||
setWindowTitle(p_title);
|
||||
|
||||
connect(m_linkTextEdit, &QLineEdit::textChanged,
|
||||
this, &VInsertLinkDialog::handleInputChanged);
|
||||
connect(m_linkUrlEdit, &QLineEdit::textChanged,
|
||||
this, &VInsertLinkDialog::handleInputChanged);
|
||||
}
|
||||
|
||||
void VInsertLinkDialog::handleInputChanged()
|
||||
{
|
||||
bool textOk = true;
|
||||
if (m_linkTextEdit->getEvaluatedText().isEmpty()) {
|
||||
textOk = false;
|
||||
}
|
||||
|
||||
bool urlOk = true;
|
||||
if (m_linkUrlEdit->text().isEmpty()) {
|
||||
urlOk = false;
|
||||
}
|
||||
|
||||
QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
|
||||
okBtn->setEnabled(textOk && urlOk);
|
||||
}
|
||||
|
||||
void VInsertLinkDialog::fetchLinkFromClipboard()
|
||||
{
|
||||
if (!m_linkUrlEdit->text().isEmpty()
|
||||
|| !m_linkTextEdit->text().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
|
||||
if (!mimeData->hasText()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString text = mimeData->text();
|
||||
if (text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl url = QUrl::fromUserInput(text);
|
||||
if (url.isValid()) {
|
||||
if (m_linkUrlEdit->text().isEmpty()) {
|
||||
m_linkUrlEdit->setText(text);
|
||||
}
|
||||
} else if (m_linkTextEdit->text().isEmpty()) {
|
||||
m_linkTextEdit->setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
QString VInsertLinkDialog::getLinkText() const
|
||||
{
|
||||
return m_linkTextEdit->getEvaluatedText();
|
||||
}
|
||||
|
||||
QString VInsertLinkDialog::getLinkUrl() const
|
||||
{
|
||||
return m_linkUrlEdit->text();
|
||||
}
|
46
src/dialog/vinsertlinkdialog.h
Normal file
46
src/dialog/vinsertlinkdialog.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef VINSERTLINKDIALOG_H
|
||||
#define VINSERTLINKDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
class VLineEdit;
|
||||
class QLineEdit;
|
||||
class QDialogButtonBox;
|
||||
|
||||
class VInsertLinkDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VInsertLinkDialog(const QString &p_title,
|
||||
const QString &p_text,
|
||||
const QString &p_info,
|
||||
const QString &p_linkText,
|
||||
const QString &p_linkUrl,
|
||||
QWidget *p_parent = nullptr);
|
||||
|
||||
QString getLinkText() const;
|
||||
|
||||
QString getLinkUrl() const;
|
||||
|
||||
private slots:
|
||||
void handleInputChanged();
|
||||
|
||||
private:
|
||||
void setupUI(const QString &p_title,
|
||||
const QString &p_text,
|
||||
const QString &p_info,
|
||||
const QString &p_linkText,
|
||||
const QString &p_linkUrl);
|
||||
|
||||
// Infer link text/url from clipboard only when text and url are both empty.
|
||||
void fetchLinkFromClipboard();
|
||||
|
||||
VLineEdit *m_linkTextEdit;
|
||||
|
||||
QLineEdit *m_linkUrlEdit;
|
||||
|
||||
QDialogButtonBox *m_btnBox;
|
||||
};
|
||||
|
||||
#endif // VINSERTLINKDIALOG_H
|
15
src/resources/icons/link.svg
Normal file
15
src/resources/icons/link.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M256.5,208H256v0C256.2,208,256.3,208,256.5,208z"/>
|
||||
<path d="M368.5,160H320c0,0,26,17,31.6,48H368h0.5c17.6,0,31.5,13.9,31.5,31.5v32c0,17.6-13.9,32.5-31.5,32.5h-112
|
||||
c-17.6,0-32.5-14.9-32.5-32.5V240h-48v31.5c0,11.5,2.5,22.5,6.9,32.5c12.6,28.2,40.9,48,73.6,48h112c44.2,0,79.5-36.3,79.5-80.5
|
||||
v-32C448,195.3,412.7,160,368.5,160z"/>
|
||||
<path d="M329.6,208c-12.1-28.3-40.1-48-73.1-48h-112c-44.2,0-80.5,35.3-80.5,79.5v32c0,44.2,36.3,80.5,80.5,80.5H192
|
||||
c0,0-25.8-17-32.1-48h-15.4c-17.6,0-32.5-14.9-32.5-32.5v-32c0-17.6,14.9-31.5,32.5-31.5H256h0.5c17.6,0,31.5,13.9,31.5,31.5v32
|
||||
c0,0.2,0,0.3,0,0.5h48c0-0.2,0-0.3,0-0.5v-32C336,228.3,333.7,217.6,329.6,208z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -80,7 +80,8 @@ SOURCES += main.cpp\
|
||||
vfilesessioninfo.cpp \
|
||||
vtableofcontent.cpp \
|
||||
utils/vmetawordmanager.cpp \
|
||||
vlineedit.cpp
|
||||
vlineedit.cpp \
|
||||
dialog/vinsertlinkdialog.cpp
|
||||
|
||||
HEADERS += vmainwindow.h \
|
||||
vdirectorytree.h \
|
||||
@ -148,7 +149,8 @@ HEADERS += vmainwindow.h \
|
||||
vfilesessioninfo.h \
|
||||
vtableofcontent.h \
|
||||
utils/vmetawordmanager.h \
|
||||
vlineedit.h
|
||||
vlineedit.h \
|
||||
dialog/vinsertlinkdialog.h
|
||||
|
||||
RESOURCES += \
|
||||
vnote.qrc \
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "utils/vmetawordmanager.h"
|
||||
#include "veditoperations.h"
|
||||
#include "vedittab.h"
|
||||
|
||||
#include "dialog/vinsertlinkdialog.h"
|
||||
|
||||
extern VConfigManager *g_config;
|
||||
|
||||
@ -199,6 +199,49 @@ void VEdit::insertImage()
|
||||
}
|
||||
}
|
||||
|
||||
void VEdit::insertLink()
|
||||
{
|
||||
if (!m_editOps) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString text;
|
||||
QString linkText, linkUrl;
|
||||
QTextCursor cursor = textCursor();
|
||||
if (cursor.hasSelection()) {
|
||||
text = VEditUtils::selectedText(cursor).trimmed();
|
||||
// Only pure space is accepted.
|
||||
QRegExp reg("[\\S ]*");
|
||||
if (reg.exactMatch(text)) {
|
||||
QUrl url = QUrl::fromUserInput(text,
|
||||
m_file->fetchBasePath());
|
||||
QRegExp urlReg("[\\.\\\\/]");
|
||||
if (url.isValid()
|
||||
&& text.contains(urlReg)) {
|
||||
// Url.
|
||||
linkUrl = text;
|
||||
} else {
|
||||
// Text.
|
||||
linkText = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VInsertLinkDialog dialog(tr("Insert Link"),
|
||||
"",
|
||||
"",
|
||||
linkText,
|
||||
linkUrl,
|
||||
this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
linkText = dialog.getLinkText();
|
||||
linkUrl = dialog.getLinkUrl();
|
||||
Q_ASSERT(!linkText.isEmpty() && !linkUrl.isEmpty());
|
||||
|
||||
m_editOps->insertLink(linkText, linkUrl);
|
||||
}
|
||||
}
|
||||
|
||||
bool VEdit::peekText(const QString &p_text, uint p_options, bool p_forward)
|
||||
{
|
||||
if (p_text.isEmpty()) {
|
||||
|
@ -91,6 +91,9 @@ public:
|
||||
// User requests to insert an image.
|
||||
virtual void insertImage();
|
||||
|
||||
// User requests to insert a link.
|
||||
virtual void insertLink();
|
||||
|
||||
// Used for incremental search.
|
||||
// User has enter the content to search, but does not enter the "find" button yet.
|
||||
bool peekText(const QString &p_text, uint p_options, bool p_forward = true);
|
||||
|
@ -90,3 +90,10 @@ void VEditOperations::requestUpdateVimStatus()
|
||||
{
|
||||
emit vimStatusUpdated(m_vim);
|
||||
}
|
||||
|
||||
void VEditOperations::setVimMode(VimMode p_mode)
|
||||
{
|
||||
if (m_vim && m_editConfig->m_enableVimMode) {
|
||||
m_vim->setMode(p_mode);
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,18 @@ class VEditOperations: public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
VEditOperations(VEdit *p_editor, VFile *p_file);
|
||||
|
||||
virtual ~VEditOperations();
|
||||
|
||||
virtual bool insertImageFromMimeData(const QMimeData *source) = 0;
|
||||
|
||||
virtual bool insertImage() = 0;
|
||||
|
||||
virtual bool insertImageFromURL(const QUrl &p_imageUrl) = 0;
|
||||
|
||||
virtual bool insertLink(const QString &p_linkText,
|
||||
const QString &p_linkUrl) = 0;
|
||||
|
||||
// Return true if @p_event has been handled and no need to be further
|
||||
// processed.
|
||||
virtual bool handleKeyPressEvent(QKeyEvent *p_event) = 0;
|
||||
@ -63,11 +70,4 @@ protected:
|
||||
VVim *m_vim;
|
||||
};
|
||||
|
||||
inline void VEditOperations::setVimMode(VimMode p_mode)
|
||||
{
|
||||
if (m_vim) {
|
||||
m_vim->setMode(p_mode);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VEDITOPERATIONS_H
|
||||
|
@ -120,3 +120,7 @@ bool VEditTab::tabHasFocus() const
|
||||
QWidget *wid = QApplication::focusWidget();
|
||||
return wid == this || isAncestorOf(wid);
|
||||
}
|
||||
|
||||
void VEditTab::insertLink()
|
||||
{
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ public:
|
||||
// User requests to insert image.
|
||||
virtual void insertImage() = 0;
|
||||
|
||||
// User requests to insert link.
|
||||
virtual void insertLink();
|
||||
|
||||
// Search @p_text in current note.
|
||||
virtual void findText(const QString &p_text, uint p_options, bool p_peek,
|
||||
bool p_forward = true) = 0;
|
||||
|
@ -463,6 +463,19 @@ void VMainWindow::initEditToolBar(QSize p_iconSize)
|
||||
|
||||
m_editToolBar->addAction(inlineCodeAct);
|
||||
|
||||
// Insert link.
|
||||
QAction *insetLinkAct = new QAction(QIcon(":/resources/icons/link.svg"),
|
||||
tr("Insert Link (Ctrl+L)"), this);
|
||||
insetLinkAct->setStatusTip(tr("Insert a link"));
|
||||
connect(insetLinkAct, &QAction::triggered,
|
||||
this, [this]() {
|
||||
if (m_curTab) {
|
||||
m_curTab->insertLink();
|
||||
}
|
||||
});
|
||||
|
||||
m_editToolBar->addAction(insetLinkAct);
|
||||
|
||||
// Insert image.
|
||||
QAction *insertImageAct = new QAction(QIcon(":/resources/icons/insert_image.svg"),
|
||||
tr("Insert Image"),
|
||||
|
@ -278,6 +278,17 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_L:
|
||||
{
|
||||
if (modifiers == Qt::ControlModifier) {
|
||||
m_editor->insertLink();
|
||||
p_event->accept();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_O:
|
||||
{
|
||||
if (modifiers == Qt::ControlModifier) {
|
||||
@ -832,3 +843,16 @@ void VMdEditOperations::decorateStrikethrough()
|
||||
cursor.endEditBlock();
|
||||
m_editor->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
bool VMdEditOperations::insertLink(const QString &p_linkText,
|
||||
const QString &p_linkUrl)
|
||||
{
|
||||
QString link = QString("[%1](%2)").arg(p_linkText).arg(p_linkUrl);
|
||||
QTextCursor cursor = m_editor->textCursor();
|
||||
cursor.insertText(link);
|
||||
m_editor->setTextCursor(cursor);
|
||||
|
||||
setVimMode(VimMode::Insert);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -16,11 +16,18 @@ class VMdEditOperations : public VEditOperations
|
||||
Q_OBJECT
|
||||
public:
|
||||
VMdEditOperations(VEdit *p_editor, VFile *p_file);
|
||||
|
||||
bool insertImageFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE;
|
||||
|
||||
bool insertImage() Q_DECL_OVERRIDE;
|
||||
|
||||
bool handleKeyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
|
||||
|
||||
bool insertImageFromURL(const QUrl &p_imageUrl) Q_DECL_OVERRIDE;
|
||||
|
||||
bool insertLink(const QString &p_linkText,
|
||||
const QString &p_linkUrl);
|
||||
|
||||
// Insert decoration markers or decorate selected text.
|
||||
// If it is Vim Normal mode, change to Insert mode first.
|
||||
void decorateText(TextDecoration p_decoration) Q_DECL_OVERRIDE;
|
||||
|
@ -469,6 +469,16 @@ void VMdTab::insertImage()
|
||||
m_editor->insertImage();
|
||||
}
|
||||
|
||||
void VMdTab::insertLink()
|
||||
{
|
||||
if (!m_isEditMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_editor);
|
||||
m_editor->insertLink();
|
||||
}
|
||||
|
||||
void VMdTab::findText(const QString &p_text, uint p_options, bool p_peek,
|
||||
bool p_forward)
|
||||
{
|
||||
|
@ -36,6 +36,8 @@ public:
|
||||
|
||||
void insertImage() Q_DECL_OVERRIDE;
|
||||
|
||||
void insertLink() Q_DECL_OVERRIDE;
|
||||
|
||||
// Search @p_text in current note.
|
||||
void findText(const QString &p_text, uint p_options, bool p_peek,
|
||||
bool p_forward = true) Q_DECL_OVERRIDE;
|
||||
|
@ -132,5 +132,6 @@
|
||||
<file>resources/icons/create_subdir.svg</file>
|
||||
<file>resources/icons/compact_mode.svg</file>
|
||||
<file>resources/icons/heading_sequence.svg</file>
|
||||
<file>resources/icons/link.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
x
Reference in New Issue
Block a user