mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
improve Snippet support
This commit is contained in:
parent
d1d8fabb60
commit
58e8ea5ee8
@ -1 +1 @@
|
|||||||
Subproject commit 98274148a0e1ad371f29abe072fac35bf5d7b6df
|
Subproject commit 7045758b2c9c10f6b72b97f15c40ded97db6ac0d
|
@ -49,6 +49,7 @@ namespace vnotex
|
|||||||
FindAndReplace,
|
FindAndReplace,
|
||||||
FindNext,
|
FindNext,
|
||||||
FindPrevious,
|
FindPrevious,
|
||||||
|
ApplySnippet,
|
||||||
MaxShortcut
|
MaxShortcut
|
||||||
};
|
};
|
||||||
Q_ENUM(Shortcut)
|
Q_ENUM(Shortcut)
|
||||||
|
@ -117,4 +117,5 @@ QString MainConfig::getVersion(const QJsonObject &p_jobj)
|
|||||||
void MainConfig::doVersionSpecificOverride()
|
void MainConfig::doVersionSpecificOverride()
|
||||||
{
|
{
|
||||||
// In a new version, we may want to change one value by force.
|
// In a new version, we may want to change one value by force.
|
||||||
|
m_coreConfig->m_shortcuts[CoreConfig::Shortcut::SearchDock].clear();
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
"CloseTab" : "Ctrl+G, X",
|
"CloseTab" : "Ctrl+G, X",
|
||||||
"NavigationDock" : "Ctrl+G, A",
|
"NavigationDock" : "Ctrl+G, A",
|
||||||
"OutlineDock" : "Ctrl+G, U",
|
"OutlineDock" : "Ctrl+G, U",
|
||||||
"SearchDock" : "Ctrl+G, S",
|
"SearchDock" : "",
|
||||||
"SnippetDock" : "",
|
"SnippetDock" : "Ctrl+G, S",
|
||||||
"LocationListDock" : "Ctrl+G, L",
|
"LocationListDock" : "Ctrl+G, L",
|
||||||
"Search" : "Ctrl+Alt+F",
|
"Search" : "Ctrl+Alt+F",
|
||||||
"NavigationMode" : "Ctrl+G, W",
|
"NavigationMode" : "Ctrl+G, W",
|
||||||
@ -93,7 +93,8 @@
|
|||||||
"RichPaste" : "Ctrl+Shift+V",
|
"RichPaste" : "Ctrl+Shift+V",
|
||||||
"FindAndReplace" : "Ctrl+F",
|
"FindAndReplace" : "Ctrl+F",
|
||||||
"FindNext" : "F3",
|
"FindNext" : "F3",
|
||||||
"FindPrevious" : "Shift+F3"
|
"FindPrevious" : "Shift+F3",
|
||||||
|
"ApplySnippet" : "Ctrl+G, I"
|
||||||
},
|
},
|
||||||
"spell_check_auto_detect_language" : false,
|
"spell_check_auto_detect_language" : false,
|
||||||
"spell_check_default_dictionary" : "en_US"
|
"spell_check_default_dictionary" : "en_US"
|
||||||
|
@ -9,6 +9,7 @@ DynamicSnippet::DynamicSnippet(const QString &p_name,
|
|||||||
const Callback &p_callback)
|
const Callback &p_callback)
|
||||||
: Snippet(p_name,
|
: Snippet(p_name,
|
||||||
p_description,
|
p_description,
|
||||||
|
QString(),
|
||||||
Snippet::InvalidShortcut,
|
Snippet::InvalidShortcut,
|
||||||
false,
|
false,
|
||||||
QString(),
|
QString(),
|
||||||
|
@ -16,6 +16,7 @@ Snippet::Snippet(const QString &p_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Snippet::Snippet(const QString &p_name,
|
Snippet::Snippet(const QString &p_name,
|
||||||
|
const QString &p_description,
|
||||||
const QString &p_content,
|
const QString &p_content,
|
||||||
int p_shortcut,
|
int p_shortcut,
|
||||||
bool p_indentAsFirstLine,
|
bool p_indentAsFirstLine,
|
||||||
@ -23,6 +24,7 @@ Snippet::Snippet(const QString &p_name,
|
|||||||
const QString &p_selectionMark)
|
const QString &p_selectionMark)
|
||||||
: m_type(Type::Text),
|
: m_type(Type::Text),
|
||||||
m_name(p_name),
|
m_name(p_name),
|
||||||
|
m_description(p_description),
|
||||||
m_content(p_content),
|
m_content(p_content),
|
||||||
m_shortcut(p_shortcut),
|
m_shortcut(p_shortcut),
|
||||||
m_indentAsFirstLine(p_indentAsFirstLine),
|
m_indentAsFirstLine(p_indentAsFirstLine),
|
||||||
@ -36,6 +38,7 @@ QJsonObject Snippet::toJson() const
|
|||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
|
|
||||||
obj[QStringLiteral("type")] = static_cast<int>(m_type);
|
obj[QStringLiteral("type")] = static_cast<int>(m_type);
|
||||||
|
obj[QStringLiteral("description")] = m_description;
|
||||||
obj[QStringLiteral("content")] = m_content;
|
obj[QStringLiteral("content")] = m_content;
|
||||||
obj[QStringLiteral("shortcut")] = m_shortcut;
|
obj[QStringLiteral("shortcut")] = m_shortcut;
|
||||||
obj[QStringLiteral("indent_as_first_line")] = m_indentAsFirstLine;
|
obj[QStringLiteral("indent_as_first_line")] = m_indentAsFirstLine;
|
||||||
@ -48,6 +51,7 @@ QJsonObject Snippet::toJson() const
|
|||||||
void Snippet::fromJson(const QJsonObject &p_jobj)
|
void Snippet::fromJson(const QJsonObject &p_jobj)
|
||||||
{
|
{
|
||||||
m_type = static_cast<Type>(p_jobj[QStringLiteral("type")].toInt());
|
m_type = static_cast<Type>(p_jobj[QStringLiteral("type")].toInt());
|
||||||
|
m_description = p_jobj[QStringLiteral("description")].toString();
|
||||||
m_content = p_jobj[QStringLiteral("content")].toString();
|
m_content = p_jobj[QStringLiteral("content")].toString();
|
||||||
m_shortcut = p_jobj[QStringLiteral("shortcut")].toInt();
|
m_shortcut = p_jobj[QStringLiteral("shortcut")].toInt();
|
||||||
m_indentAsFirstLine = p_jobj[QStringLiteral("indent_as_first_line")].toBool();
|
m_indentAsFirstLine = p_jobj[QStringLiteral("indent_as_first_line")].toBool();
|
||||||
@ -104,6 +108,11 @@ const QString &Snippet::getContent() const
|
|||||||
return m_content;
|
return m_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString &Snippet::getDescription() const
|
||||||
|
{
|
||||||
|
return m_description;
|
||||||
|
}
|
||||||
|
|
||||||
QString Snippet::apply(const QString &p_selectedText,
|
QString Snippet::apply(const QString &p_selectedText,
|
||||||
const QString &p_indentationSpaces,
|
const QString &p_indentationSpaces,
|
||||||
int &p_cursorOffset)
|
int &p_cursorOffset)
|
||||||
|
@ -24,6 +24,7 @@ namespace vnotex
|
|||||||
explicit Snippet(const QString &p_name);
|
explicit Snippet(const QString &p_name);
|
||||||
|
|
||||||
Snippet(const QString &p_name,
|
Snippet(const QString &p_name,
|
||||||
|
const QString &p_description,
|
||||||
const QString &p_content,
|
const QString &p_content,
|
||||||
int p_shortcut,
|
int p_shortcut,
|
||||||
bool p_indentAsFirstLine,
|
bool p_indentAsFirstLine,
|
||||||
@ -43,6 +44,8 @@ namespace vnotex
|
|||||||
|
|
||||||
const QString &getName() const;
|
const QString &getName() const;
|
||||||
|
|
||||||
|
const QString &getDescription() const;
|
||||||
|
|
||||||
Type getType() const;
|
Type getType() const;
|
||||||
|
|
||||||
int getShortcut() const;
|
int getShortcut() const;
|
||||||
@ -78,6 +81,8 @@ namespace vnotex
|
|||||||
// To avoid mixed with shortcut, the name should not contain digits.
|
// To avoid mixed with shortcut, the name should not contain digits.
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
|
||||||
|
QString m_description;
|
||||||
|
|
||||||
// Content of the snippet if it is Text.
|
// Content of the snippet if it is Text.
|
||||||
// Embedded snippet is supported.
|
// Embedded snippet is supported.
|
||||||
QString m_content;
|
QString m_content;
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
|
|
||||||
@ -81,3 +84,40 @@ QIcon IconUtils::fetchIconWithDisabledState(const QString &p_iconFile)
|
|||||||
colors.push_back(OverriddenColor(s_defaultIconDisabledForeground, QIcon::Disabled, QIcon::Off));
|
colors.push_back(OverriddenColor(s_defaultIconDisabledForeground, QIcon::Disabled, QIcon::Off));
|
||||||
return fetchIcon(p_iconFile, colors);
|
return fetchIcon(p_iconFile, colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QIcon IconUtils::drawTextIcon(const QString &p_text,
|
||||||
|
const QString &p_fg,
|
||||||
|
const QString &p_border)
|
||||||
|
{
|
||||||
|
const int wid = 64;
|
||||||
|
QPixmap pixmap(wid, wid);
|
||||||
|
pixmap.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter(&pixmap);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
auto pen = painter.pen();
|
||||||
|
pen.setColor(p_border);
|
||||||
|
pen.setWidth(3);
|
||||||
|
painter.setPen(pen);
|
||||||
|
|
||||||
|
painter.drawRoundedRect(4, 4, wid - 8, wid - 8, 8, 8);
|
||||||
|
|
||||||
|
if (!p_text.isEmpty()) {
|
||||||
|
pen.setColor(p_fg);
|
||||||
|
painter.setPen(pen);
|
||||||
|
|
||||||
|
auto font = painter.font();
|
||||||
|
font.setPointSize(36);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
auto requriedRect = painter.boundingRect(4, 4, wid - 8, wid - 8,
|
||||||
|
Qt::AlignCenter,
|
||||||
|
p_text);
|
||||||
|
painter.drawText(requriedRect, p_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon icon;
|
||||||
|
icon.addPixmap(pixmap);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
@ -46,6 +46,10 @@ namespace vnotex
|
|||||||
|
|
||||||
static QIcon fetchIconWithDisabledState(const QString &p_iconFile);
|
static QIcon fetchIconWithDisabledState(const QString &p_iconFile);
|
||||||
|
|
||||||
|
static QIcon drawTextIcon(const QString &p_text,
|
||||||
|
const QString &p_fg,
|
||||||
|
const QString &p_border);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QString replaceForegroundOfIcon(const QString &p_iconContent, const QString &p_foreground);
|
static QString replaceForegroundOfIcon(const QString &p_iconContent, const QString &p_foreground);
|
||||||
|
|
||||||
|
@ -130,6 +130,32 @@ bool WidgetUtils::processKeyEventLikeVi(QWidget *p_widget,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Qt::Key_H:
|
||||||
|
{
|
||||||
|
if (isViControlModifier(modifiers)) {
|
||||||
|
auto upEvent = new QKeyEvent(QEvent::KeyPress,
|
||||||
|
Qt::Key_Left,
|
||||||
|
Qt::NoModifier);
|
||||||
|
QCoreApplication::postEvent(p_widget, upEvent);
|
||||||
|
eventHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Qt::Key_L:
|
||||||
|
{
|
||||||
|
if (isViControlModifier(modifiers)) {
|
||||||
|
auto upEvent = new QKeyEvent(QEvent::KeyPress,
|
||||||
|
Qt::Key_Right,
|
||||||
|
Qt::NoModifier);
|
||||||
|
QCoreApplication::postEvent(p_widget, upEvent);
|
||||||
|
eventHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,12 @@ DeleteConfirmDialog::DeleteConfirmDialog(const QString &p_title,
|
|||||||
const QString &p_info,
|
const QString &p_info,
|
||||||
const QVector<ConfirmItemInfo> &p_items,
|
const QVector<ConfirmItemInfo> &p_items,
|
||||||
DeleteConfirmDialog::Flags p_flags,
|
DeleteConfirmDialog::Flags p_flags,
|
||||||
bool p_noAskChecked,
|
bool p_noAskAgainChecked,
|
||||||
QWidget *p_parent)
|
QWidget *p_parent)
|
||||||
: ScrollDialog(p_parent),
|
: ScrollDialog(p_parent),
|
||||||
m_items(p_items)
|
m_items(p_items)
|
||||||
{
|
{
|
||||||
setupUI(p_title, p_text, p_info, p_flags, p_noAskChecked);
|
setupUI(p_title, p_text, p_info, p_flags, p_noAskAgainChecked);
|
||||||
|
|
||||||
updateItemsList();
|
updateItemsList();
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ void DeleteConfirmDialog::setupUI(const QString &p_title,
|
|||||||
const QString &p_text,
|
const QString &p_text,
|
||||||
const QString &p_info,
|
const QString &p_info,
|
||||||
DeleteConfirmDialog::Flags p_flags,
|
DeleteConfirmDialog::Flags p_flags,
|
||||||
bool p_noAskChecked)
|
bool p_noAskAgainChecked)
|
||||||
{
|
{
|
||||||
auto mainWidget = new QWidget(this);
|
auto mainWidget = new QWidget(this);
|
||||||
setCentralWidget(mainWidget);
|
setCentralWidget(mainWidget);
|
||||||
@ -60,7 +60,7 @@ void DeleteConfirmDialog::setupUI(const QString &p_title,
|
|||||||
// Ask again.
|
// Ask again.
|
||||||
if (p_flags & Flag::AskAgain) {
|
if (p_flags & Flag::AskAgain) {
|
||||||
m_noAskCB = new QCheckBox(tr("Do not ask again"), mainWidget);
|
m_noAskCB = new QCheckBox(tr("Do not ask again"), mainWidget);
|
||||||
m_noAskCB->setChecked(p_noAskChecked);
|
m_noAskCB->setChecked(p_noAskAgainChecked);
|
||||||
mainLayout->addWidget(m_noAskCB);
|
mainLayout->addWidget(m_noAskCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ namespace vnotex
|
|||||||
const QString &p_info,
|
const QString &p_info,
|
||||||
const QVector<ConfirmItemInfo> &p_items,
|
const QVector<ConfirmItemInfo> &p_items,
|
||||||
DeleteConfirmDialog::Flags p_flags,
|
DeleteConfirmDialog::Flags p_flags,
|
||||||
bool p_noAskChecked,
|
bool p_noAskAgainChecked,
|
||||||
QWidget *p_parent = nullptr);
|
QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
QVector<ConfirmItemInfo> getConfirmedItems() const;
|
QVector<ConfirmItemInfo> getConfirmedItems() const;
|
||||||
@ -87,7 +87,7 @@ namespace vnotex
|
|||||||
const QString &p_text,
|
const QString &p_text,
|
||||||
const QString &p_info,
|
const QString &p_info,
|
||||||
DeleteConfirmDialog::Flags p_flags,
|
DeleteConfirmDialog::Flags p_flags,
|
||||||
bool p_noAskChecked);
|
bool p_noAskAgainChecked);
|
||||||
|
|
||||||
void updateItemsList();
|
void updateItemsList();
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ void NewSnippetDialog::acceptedButtonClicked()
|
|||||||
bool NewSnippetDialog::newSnippet()
|
bool NewSnippetDialog::newSnippet()
|
||||||
{
|
{
|
||||||
auto snip = QSharedPointer<Snippet>::create(m_infoWidget->getName(),
|
auto snip = QSharedPointer<Snippet>::create(m_infoWidget->getName(),
|
||||||
|
m_infoWidget->getDescription(),
|
||||||
m_infoWidget->getContent(),
|
m_infoWidget->getContent(),
|
||||||
m_infoWidget->getShortcut(),
|
m_infoWidget->getShortcut(),
|
||||||
m_infoWidget->shouldIndentAsFirstLine(),
|
m_infoWidget->shouldIndentAsFirstLine(),
|
||||||
|
@ -44,6 +44,11 @@ void SnippetInfoWidget::setupUI()
|
|||||||
|
|
||||||
setFocusProxy(m_nameLineEdit);
|
setFocusProxy(m_nameLineEdit);
|
||||||
|
|
||||||
|
m_descriptionLineEdit = WidgetsFactory::createLineEdit(this);
|
||||||
|
connect(m_descriptionLineEdit, &QLineEdit::textEdited,
|
||||||
|
this, &SnippetInfoWidget::inputEdited);
|
||||||
|
mainLayout->addRow(tr("Description:"), m_descriptionLineEdit);
|
||||||
|
|
||||||
setupTypeComboBox(this);
|
setupTypeComboBox(this);
|
||||||
mainLayout->addRow(tr("Type:"), m_typeComboBox);
|
mainLayout->addRow(tr("Type:"), m_typeComboBox);
|
||||||
|
|
||||||
@ -134,6 +139,11 @@ QString SnippetInfoWidget::getContent() const
|
|||||||
return m_contentTextEdit->toPlainText();
|
return m_contentTextEdit->toPlainText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString SnippetInfoWidget::getDescription() const
|
||||||
|
{
|
||||||
|
return m_descriptionLineEdit->text();
|
||||||
|
}
|
||||||
|
|
||||||
void SnippetInfoWidget::setSnippet(const Snippet *p_snippet)
|
void SnippetInfoWidget::setSnippet(const Snippet *p_snippet)
|
||||||
{
|
{
|
||||||
if (m_snippet == p_snippet) {
|
if (m_snippet == p_snippet) {
|
||||||
@ -144,15 +154,26 @@ void SnippetInfoWidget::setSnippet(const Snippet *p_snippet)
|
|||||||
m_snippet = p_snippet;
|
m_snippet = p_snippet;
|
||||||
initShortcutComboBox();
|
initShortcutComboBox();
|
||||||
if (m_snippet) {
|
if (m_snippet) {
|
||||||
|
const bool readOnly = m_snippet->isReadOnly();
|
||||||
m_nameLineEdit->setText(m_snippet->getName());
|
m_nameLineEdit->setText(m_snippet->getName());
|
||||||
|
m_nameLineEdit->setEnabled(!readOnly);
|
||||||
|
m_descriptionLineEdit->setText(m_snippet->getDescription());
|
||||||
|
m_descriptionLineEdit->setEnabled(!readOnly);
|
||||||
m_typeComboBox->setCurrentIndex(m_typeComboBox->findData(static_cast<int>(m_snippet->getType())));
|
m_typeComboBox->setCurrentIndex(m_typeComboBox->findData(static_cast<int>(m_snippet->getType())));
|
||||||
|
m_typeComboBox->setEnabled(!readOnly);
|
||||||
m_shortcutComboBox->setCurrentIndex(m_shortcutComboBox->findData(m_snippet->getShortcut()));
|
m_shortcutComboBox->setCurrentIndex(m_shortcutComboBox->findData(m_snippet->getShortcut()));
|
||||||
|
m_shortcutComboBox->setEnabled(!readOnly);
|
||||||
m_cursorMarkLineEdit->setText(m_snippet->getCursorMark());
|
m_cursorMarkLineEdit->setText(m_snippet->getCursorMark());
|
||||||
|
m_cursorMarkLineEdit->setEnabled(!readOnly);
|
||||||
m_selectionMarkLineEdit->setText(m_snippet->getSelectionMark());
|
m_selectionMarkLineEdit->setText(m_snippet->getSelectionMark());
|
||||||
|
m_selectionMarkLineEdit->setEnabled(!readOnly);
|
||||||
m_indentAsFirstLineCheckBox->setChecked(m_snippet->isIndentAsFirstLineEnabled());
|
m_indentAsFirstLineCheckBox->setChecked(m_snippet->isIndentAsFirstLineEnabled());
|
||||||
|
m_indentAsFirstLineCheckBox->setEnabled(!readOnly);
|
||||||
m_contentTextEdit->setPlainText(m_snippet->getContent());
|
m_contentTextEdit->setPlainText(m_snippet->getContent());
|
||||||
|
m_contentTextEdit->setEnabled(!readOnly);
|
||||||
} else {
|
} else {
|
||||||
m_nameLineEdit->clear();
|
m_nameLineEdit->clear();
|
||||||
|
m_descriptionLineEdit->clear();
|
||||||
m_typeComboBox->setCurrentIndex(m_typeComboBox->findData(static_cast<int>(Snippet::Type::Text)));
|
m_typeComboBox->setCurrentIndex(m_typeComboBox->findData(static_cast<int>(Snippet::Type::Text)));
|
||||||
m_shortcutComboBox->setCurrentIndex(m_shortcutComboBox->findData(Snippet::InvalidShortcut));
|
m_shortcutComboBox->setCurrentIndex(m_shortcutComboBox->findData(Snippet::InvalidShortcut));
|
||||||
m_cursorMarkLineEdit->setText(Snippet::c_defaultCursorMark);
|
m_cursorMarkLineEdit->setText(Snippet::c_defaultCursorMark);
|
||||||
|
@ -36,6 +36,8 @@ namespace vnotex
|
|||||||
|
|
||||||
QString getContent() const;
|
QString getContent() const;
|
||||||
|
|
||||||
|
QString getDescription() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void inputEdited();
|
void inputEdited();
|
||||||
|
|
||||||
@ -56,6 +58,8 @@ namespace vnotex
|
|||||||
|
|
||||||
QLineEdit *m_nameLineEdit = nullptr;
|
QLineEdit *m_nameLineEdit = nullptr;
|
||||||
|
|
||||||
|
QLineEdit *m_descriptionLineEdit = nullptr;
|
||||||
|
|
||||||
QComboBox *m_typeComboBox = nullptr;
|
QComboBox *m_typeComboBox = nullptr;
|
||||||
|
|
||||||
QComboBox *m_shortcutComboBox = nullptr;
|
QComboBox *m_shortcutComboBox = nullptr;
|
||||||
|
@ -79,6 +79,7 @@ void SnippetPropertiesDialog::acceptedButtonClicked()
|
|||||||
bool SnippetPropertiesDialog::saveSnippetProperties()
|
bool SnippetPropertiesDialog::saveSnippetProperties()
|
||||||
{
|
{
|
||||||
auto snip = QSharedPointer<Snippet>::create(m_infoWidget->getName(),
|
auto snip = QSharedPointer<Snippet>::create(m_infoWidget->getName(),
|
||||||
|
m_infoWidget->getDescription(),
|
||||||
m_infoWidget->getContent(),
|
m_infoWidget->getContent(),
|
||||||
m_infoWidget->getShortcut(),
|
m_infoWidget->getShortcut(),
|
||||||
m_infoWidget->shouldIndentAsFirstLine(),
|
m_infoWidget->shouldIndentAsFirstLine(),
|
||||||
|
32
src/widgets/floatingwidget.cpp
Normal file
32
src/widgets/floatingwidget.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "floatingwidget.h"
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
using namespace vnotex;
|
||||||
|
|
||||||
|
FloatingWidget::FloatingWidget(QWidget *p_parent)
|
||||||
|
: QWidget(p_parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::showEvent(QShowEvent *p_event)
|
||||||
|
{
|
||||||
|
QWidget::showEvent(p_event);
|
||||||
|
|
||||||
|
// May fix potential input method issue.
|
||||||
|
activateWindow();
|
||||||
|
|
||||||
|
setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::finish()
|
||||||
|
{
|
||||||
|
if (m_menu) {
|
||||||
|
m_menu->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatingWidget::setMenu(QMenu *p_menu)
|
||||||
|
{
|
||||||
|
m_menu = p_menu;
|
||||||
|
}
|
33
src/widgets/floatingwidget.h
Normal file
33
src/widgets/floatingwidget.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef FLOATINGWIDGET_H
|
||||||
|
#define FLOATINGWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
namespace vnotex
|
||||||
|
{
|
||||||
|
// Used for ViewWindow to show as a floating widget (usually via QMenu).
|
||||||
|
class FloatingWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
void setMenu(QMenu *p_menu);
|
||||||
|
|
||||||
|
virtual QVariant result() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FloatingWidget(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
// Sub-class calls this to indicates completion.
|
||||||
|
void finish();
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMenu *m_menu = nullptr;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FLOATINGWIDGET_H
|
@ -31,7 +31,6 @@
|
|||||||
#include "editors/statuswidget.h"
|
#include "editors/statuswidget.h"
|
||||||
#include "editors/plantumlhelper.h"
|
#include "editors/plantumlhelper.h"
|
||||||
#include "editors/graphvizhelper.h"
|
#include "editors/graphvizhelper.h"
|
||||||
#include <snippet/snippetmgr.h>
|
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
@ -979,13 +978,25 @@ void MarkdownViewWindow::setupPreviewHelper()
|
|||||||
|
|
||||||
void MarkdownViewWindow::applySnippet(const QString &p_name)
|
void MarkdownViewWindow::applySnippet(const QString &p_name)
|
||||||
{
|
{
|
||||||
if (isReadMode() || m_editor->isReadOnly()) {
|
if (isReadMode()) {
|
||||||
qWarning() << "failed to apply snippet in read mode or to a read-only buffer" << p_name;
|
qWarning() << "failed to apply snippet in read mode" << p_name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_editor->enterInsertModeIfApplicable();
|
TextViewWindowHelper::applySnippet(this, p_name);
|
||||||
SnippetMgr::getInst().applySnippet(p_name,
|
}
|
||||||
m_editor->getTextEdit(),
|
|
||||||
SnippetMgr::generateOverrides(getBuffer()));
|
void MarkdownViewWindow::applySnippet()
|
||||||
|
{
|
||||||
|
if (isReadMode()) {
|
||||||
|
qWarning() << "failed to apply snippet in read mode";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextViewWindowHelper::applySnippet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint MarkdownViewWindow::getFloatingWidgetPosition()
|
||||||
|
{
|
||||||
|
return TextViewWindowHelper::getFloatingWidgetPosition(this);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void applySnippet(const QString &p_name) Q_DECL_OVERRIDE;
|
void applySnippet(const QString &p_name) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void applySnippet() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void handleEditorConfigChange() Q_DECL_OVERRIDE;
|
void handleEditorConfigChange() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@ -85,6 +87,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void zoom(bool p_zoomIn) Q_DECL_OVERRIDE;
|
void zoom(bool p_zoomIn) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QPoint getFloatingWidgetPosition() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
|
|
||||||
|
233
src/widgets/quickselector.cpp
Normal file
233
src/widgets/quickselector.cpp
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#include "quickselector.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidgetAction>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
#include <utils/widgetutils.h>
|
||||||
|
#include <utils/iconutils.h>
|
||||||
|
|
||||||
|
#include "lineedit.h"
|
||||||
|
#include "listwidget.h"
|
||||||
|
#include "widgetsfactory.h"
|
||||||
|
|
||||||
|
using namespace vnotex;
|
||||||
|
|
||||||
|
QuickSelectorItem::QuickSelectorItem(const QVariant &p_key,
|
||||||
|
const QString &p_name,
|
||||||
|
const QString &p_tip,
|
||||||
|
const QString &p_shortcut)
|
||||||
|
: m_key(p_key),
|
||||||
|
m_name(p_name),
|
||||||
|
m_tip(p_tip),
|
||||||
|
m_shortcut(p_shortcut)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_shortcut.size() < 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool selectorItemCmp(const QuickSelectorItem &p_a, const QuickSelectorItem &p_b)
|
||||||
|
{
|
||||||
|
if (p_a.m_shortcut.isEmpty()) {
|
||||||
|
if (p_b.m_shortcut.isEmpty()) {
|
||||||
|
return p_a.m_name < p_b.m_name;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (p_b.m_shortcut.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p_a.m_shortcut < p_b.m_shortcut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickSelector::QuickSelector(const QString &p_title,
|
||||||
|
const QVector<QuickSelectorItem> &p_items,
|
||||||
|
bool p_sortByShortcut,
|
||||||
|
QWidget *p_parent)
|
||||||
|
: FloatingWidget(p_parent),
|
||||||
|
m_items(p_items)
|
||||||
|
{
|
||||||
|
if (p_sortByShortcut) {
|
||||||
|
std::sort(m_items.begin(), m_items.end(), selectorItemCmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupUI(p_title);
|
||||||
|
|
||||||
|
updateItemList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickSelector::setupUI(const QString &p_title)
|
||||||
|
{
|
||||||
|
auto mainLayout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
if (!p_title.isEmpty()) {
|
||||||
|
mainLayout->addWidget(new QLabel(p_title, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchLineEdit = WidgetsFactory::createLineEdit(this);
|
||||||
|
connect(m_searchLineEdit, &QLineEdit::textEdited,
|
||||||
|
this, &QuickSelector::searchAndFilter);
|
||||||
|
mainLayout->addWidget(m_searchLineEdit);
|
||||||
|
|
||||||
|
setFocusProxy(m_searchLineEdit);
|
||||||
|
m_searchLineEdit->installEventFilter(this);
|
||||||
|
|
||||||
|
m_itemList = new ListWidget(this);
|
||||||
|
m_itemList->setWrapping(true);
|
||||||
|
m_itemList->setFlow(QListView::LeftToRight);
|
||||||
|
m_itemList->setIconSize(QSize(18, 18));
|
||||||
|
connect(m_itemList, &QListWidget::itemActivated,
|
||||||
|
this, &QuickSelector::activateItem);
|
||||||
|
mainLayout->addWidget(m_itemList);
|
||||||
|
|
||||||
|
m_itemList->installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickSelector::updateItemList()
|
||||||
|
{
|
||||||
|
m_itemList->clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < m_items.size(); ++i) {
|
||||||
|
const auto &item = m_items[i];
|
||||||
|
|
||||||
|
auto listItem = new QListWidgetItem(m_itemList);
|
||||||
|
auto icon = IconUtils::drawTextIcon(item.m_shortcut, "blue", "darkgreen");
|
||||||
|
listItem->setIcon(icon);
|
||||||
|
|
||||||
|
listItem->setText(item.m_name);
|
||||||
|
listItem->setToolTip(item.m_tip);
|
||||||
|
listItem->setData(Qt::UserRole, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!m_items.isEmpty());
|
||||||
|
m_itemList->setCurrentRow(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickSelector::activateItem(const QListWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
if (p_item) {
|
||||||
|
m_selectedKey = getSelectorItem(p_item).m_key;
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickSelector::activate(const QuickSelectorItem *p_item)
|
||||||
|
{
|
||||||
|
m_selectedKey = p_item->m_key;
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickSelectorItem &QuickSelector::getSelectorItem(const QListWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_item);
|
||||||
|
return m_items[p_item->data(Qt::UserRole).toInt()];
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant QuickSelector::result() const
|
||||||
|
{
|
||||||
|
return m_selectedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QuickSelector::eventFilter(QObject *p_obj, QEvent *p_event)
|
||||||
|
{
|
||||||
|
if ((p_obj == m_searchLineEdit || p_obj == m_itemList)
|
||||||
|
&& p_event->type() == QEvent::KeyPress) {
|
||||||
|
auto keyEve = static_cast<QKeyEvent *>(p_event);
|
||||||
|
const auto key = keyEve->key();
|
||||||
|
if (key == Qt::Key_Tab || key == Qt::Key_Backtab) {
|
||||||
|
// Change focus.
|
||||||
|
if (p_obj == m_searchLineEdit) {
|
||||||
|
m_itemList->setFocus();
|
||||||
|
} else {
|
||||||
|
m_searchLineEdit->setFocus();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (key == Qt::Key_Enter || key == Qt::Key_Return) {
|
||||||
|
if (p_obj == m_searchLineEdit) {
|
||||||
|
activateItem(m_itemList->currentItem());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FloatingWidget::eventFilter(p_obj, p_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuickSelector::searchAndFilter(const QString &p_text)
|
||||||
|
{
|
||||||
|
auto text = p_text.trimmed();
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
// Show all items.
|
||||||
|
filterItems([](const QuickSelectorItem &) {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (text.size() < 3) {
|
||||||
|
// Check shortcut first.
|
||||||
|
const QuickSelectorItem *hitItem = nullptr;
|
||||||
|
int ret = filterItems([&text, &hitItem](const QuickSelectorItem &p_item) {
|
||||||
|
if (p_item.m_shortcut == text) {
|
||||||
|
hitItem = &p_item;
|
||||||
|
return true;
|
||||||
|
} else if (p_item.m_shortcut.startsWith(text)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hitItem) {
|
||||||
|
activate(hitItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check name.
|
||||||
|
auto parts = text.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||||||
|
Q_ASSERT(!parts.isEmpty());
|
||||||
|
QRegularExpression regExp;
|
||||||
|
regExp.setPatternOptions(regExp.patternOptions() | QRegularExpression::CaseInsensitiveOption);
|
||||||
|
if (parts.size() == 1) {
|
||||||
|
regExp.setPattern(QRegularExpression::escape(parts[0]));
|
||||||
|
} else {
|
||||||
|
QString pattern = QRegularExpression::escape(parts[0]);
|
||||||
|
for (int i = 1; i < parts.size(); ++i) {
|
||||||
|
pattern += ".*" + QRegularExpression::escape(parts[i]);
|
||||||
|
}
|
||||||
|
regExp.setPattern(pattern);
|
||||||
|
}
|
||||||
|
filterItems([®Exp](const QuickSelectorItem &p_item) {
|
||||||
|
if (p_item.m_name.indexOf(regExp) != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuickSelector::filterItems(const std::function<bool(const QuickSelectorItem &)> &p_judge)
|
||||||
|
{
|
||||||
|
const int cnt = m_itemList->count();
|
||||||
|
int matchedCnt = 0;
|
||||||
|
int firstHit = -1;
|
||||||
|
for (int i = 0; i < cnt; ++i) {
|
||||||
|
auto item = m_itemList->item(i);
|
||||||
|
bool hit = p_judge(getSelectorItem(item));
|
||||||
|
if (hit) {
|
||||||
|
if (matchedCnt == 0) {
|
||||||
|
firstHit = i;
|
||||||
|
}
|
||||||
|
++matchedCnt;
|
||||||
|
}
|
||||||
|
item->setHidden(!hit);
|
||||||
|
}
|
||||||
|
m_itemList->setCurrentRow(firstHit);
|
||||||
|
return matchedCnt;
|
||||||
|
}
|
74
src/widgets/quickselector.h
Normal file
74
src/widgets/quickselector.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef QUICKSELECTOR_H
|
||||||
|
#define QUICKSELECTOR_H
|
||||||
|
|
||||||
|
#include "floatingwidget.h"
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
class QListWidget;
|
||||||
|
class QListWidgetItem;
|
||||||
|
|
||||||
|
namespace vnotex
|
||||||
|
{
|
||||||
|
struct QuickSelectorItem
|
||||||
|
{
|
||||||
|
QuickSelectorItem() = default;
|
||||||
|
|
||||||
|
QuickSelectorItem(const QVariant &p_key,
|
||||||
|
const QString &p_name,
|
||||||
|
const QString &p_tip,
|
||||||
|
const QString &p_shortcut);
|
||||||
|
|
||||||
|
QVariant m_key;
|
||||||
|
|
||||||
|
QString m_name;
|
||||||
|
|
||||||
|
QString m_tip;
|
||||||
|
|
||||||
|
// Empty or size < 3.
|
||||||
|
QString m_shortcut;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QuickSelector : public FloatingWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QuickSelector(const QString &p_title,
|
||||||
|
const QVector<QuickSelectorItem> &p_items,
|
||||||
|
bool p_sortByShortcut,
|
||||||
|
QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
QVariant result() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *p_obj, QEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI(const QString &p_title);
|
||||||
|
|
||||||
|
void updateItemList();
|
||||||
|
|
||||||
|
void activateItem(const QListWidgetItem *p_item);
|
||||||
|
|
||||||
|
void activate(const QuickSelectorItem *p_item);
|
||||||
|
|
||||||
|
void searchAndFilter(const QString &p_text);
|
||||||
|
|
||||||
|
// Return the number of items that hit @p_judge.
|
||||||
|
int filterItems(const std::function<bool(const QuickSelectorItem &)> &p_judge);
|
||||||
|
|
||||||
|
QuickSelectorItem &getSelectorItem(const QListWidgetItem *p_item);
|
||||||
|
|
||||||
|
QVector<QuickSelectorItem> m_items;
|
||||||
|
|
||||||
|
QLineEdit *m_searchLineEdit = nullptr;
|
||||||
|
|
||||||
|
QListWidget *m_itemList = nullptr;
|
||||||
|
|
||||||
|
QVariant m_selectedKey;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // QUICKSELECTOR_H
|
@ -103,6 +103,7 @@ void SnippetPanel::updateSnippetList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
item->setData(Qt::UserRole, snippet->getName());
|
item->setData(Qt::UserRole, snippet->getName());
|
||||||
|
item->setToolTip(snippet->getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
updateItemsCountLabel();
|
updateItemsCountLabel();
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include <core/thememgr.h>
|
#include <core/thememgr.h>
|
||||||
#include "editors/statuswidget.h"
|
#include "editors/statuswidget.h"
|
||||||
#include <core/fileopenparameters.h>
|
#include <core/fileopenparameters.h>
|
||||||
#include <snippet/snippetmgr.h>
|
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
@ -257,13 +256,15 @@ ViewWindowSession TextViewWindow::saveSession() const
|
|||||||
|
|
||||||
void TextViewWindow::applySnippet(const QString &p_name)
|
void TextViewWindow::applySnippet(const QString &p_name)
|
||||||
{
|
{
|
||||||
if (m_editor->isReadOnly()) {
|
TextViewWindowHelper::applySnippet(this, p_name);
|
||||||
qWarning() << "failed to apply snippet to a read-only buffer" << p_name;
|
}
|
||||||
return;
|
|
||||||
}
|
void TextViewWindow::applySnippet()
|
||||||
|
{
|
||||||
m_editor->enterInsertModeIfApplicable();
|
TextViewWindowHelper::applySnippet(this);
|
||||||
SnippetMgr::getInst().applySnippet(p_name,
|
}
|
||||||
m_editor->getTextEdit(),
|
|
||||||
SnippetMgr::generateOverrides(getBuffer()));
|
QPoint TextViewWindow::getFloatingWidgetPosition()
|
||||||
|
{
|
||||||
|
return TextViewWindowHelper::getFloatingWidgetPosition(this);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void applySnippet(const QString &p_name) Q_DECL_OVERRIDE;
|
void applySnippet(const QString &p_name) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void applySnippet() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void handleEditorConfigChange() Q_DECL_OVERRIDE;
|
void handleEditorConfigChange() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@ -62,6 +64,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void zoom(bool p_zoomIn) Q_DECL_OVERRIDE;
|
void zoom(bool p_zoomIn) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QPoint getFloatingWidgetPosition() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
|
|
||||||
|
@ -2,11 +2,17 @@
|
|||||||
#define TEXTVIEWWINDOWHELPER_H
|
#define TEXTVIEWWINDOWHELPER_H
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QTextCursor>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QTextBlock>
|
||||||
|
|
||||||
#include <vtextedit/texteditorconfig.h>
|
#include <vtextedit/texteditorconfig.h>
|
||||||
#include <core/texteditorconfig.h>
|
#include <core/texteditorconfig.h>
|
||||||
#include <core/configmgr.h>
|
#include <core/configmgr.h>
|
||||||
#include <utils/widgetutils.h>
|
#include <utils/widgetutils.h>
|
||||||
|
#include <snippet/snippetmgr.h>
|
||||||
|
|
||||||
|
#include "quickselector.h"
|
||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
@ -181,6 +187,104 @@ namespace vnotex
|
|||||||
p_win->m_editor->clearIncrementalSearchHighlight();
|
p_win->m_editor->clearIncrementalSearchHighlight();
|
||||||
p_win->m_editor->clearSearchHighlight();
|
p_win->m_editor->clearSearchHighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename _ViewWindow>
|
||||||
|
static void applySnippet(_ViewWindow *p_win, const QString &p_name)
|
||||||
|
{
|
||||||
|
if (p_win->m_editor->isReadOnly() || p_name.isEmpty()) {
|
||||||
|
qWarning() << "failed to apply snippet" << p_name << "to a read-only buffer";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SnippetMgr::getInst().applySnippet(p_name,
|
||||||
|
p_win->m_editor->getTextEdit(),
|
||||||
|
SnippetMgr::generateOverrides(p_win->getBuffer()));
|
||||||
|
p_win->m_editor->enterInsertModeIfApplicable();
|
||||||
|
p_win->showMessage(ViewWindow::tr("Snippet applied: %1").arg(p_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _ViewWindow>
|
||||||
|
static void applySnippet(_ViewWindow *p_win)
|
||||||
|
{
|
||||||
|
if (p_win->m_editor->isReadOnly()) {
|
||||||
|
qWarning() << "failed to apply snippet to a read-only buffer";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString snippetName;
|
||||||
|
|
||||||
|
auto textEdit = p_win->m_editor->getTextEdit();
|
||||||
|
if (!textEdit->hasSelection()) {
|
||||||
|
// Fetch the snippet symbol containing current cursor.
|
||||||
|
auto cursor = textEdit->textCursor();
|
||||||
|
const auto block = cursor.block();
|
||||||
|
const auto text = block.text();
|
||||||
|
const int pib = cursor.positionInBlock();
|
||||||
|
QRegularExpression regExp(SnippetMgr::c_snippetSymbolRegExp);
|
||||||
|
QRegularExpressionMatch match;
|
||||||
|
int idx = text.lastIndexOf(regExp, pib, &match);
|
||||||
|
if (idx >= 0 && (idx + match.capturedLength(0) >= pib)) {
|
||||||
|
// Found one symbol under current cursor.
|
||||||
|
snippetName = match.captured(1);
|
||||||
|
if (!SnippetMgr::getInst().find(snippetName)) {
|
||||||
|
p_win->showMessage(ViewWindow::tr("Snippet (%1) not found").arg(snippetName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the symbol and apply snippet later.
|
||||||
|
cursor.setPosition(block.position() + idx);
|
||||||
|
cursor.setPosition(block.position() + idx + match.capturedLength(0), QTextCursor::KeepAnchor);
|
||||||
|
cursor.removeSelectedText();
|
||||||
|
textEdit->setTextCursor(cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snippetName.isEmpty()) {
|
||||||
|
// Prompt for snippet.
|
||||||
|
snippetName = promptForSnippet(p_win);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!snippetName.isEmpty()) {
|
||||||
|
applySnippet(p_win, snippetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _ViewWindow>
|
||||||
|
static QString promptForSnippet(_ViewWindow *p_win)
|
||||||
|
{
|
||||||
|
const auto snippets = SnippetMgr::getInst().getSnippets();
|
||||||
|
if (snippets.isEmpty()) {
|
||||||
|
p_win->showMessage(ViewWindow::tr("Snippet not available"));
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QuickSelectorItem> items;
|
||||||
|
for (const auto &snip : snippets) {
|
||||||
|
items.push_back(QuickSelectorItem(snip->getName(),
|
||||||
|
snip->getName(),
|
||||||
|
snip->getDescription(),
|
||||||
|
snip->getShortcutString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ownership will be transferred to showFloatingWidget().
|
||||||
|
auto selector = new QuickSelector(ViewWindow::tr("Select Snippet"),
|
||||||
|
items,
|
||||||
|
true,
|
||||||
|
p_win);
|
||||||
|
auto ret = p_win->showFloatingWidget(selector);
|
||||||
|
return ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _ViewWindow>
|
||||||
|
static QPoint getFloatingWidgetPosition(_ViewWindow *p_win)
|
||||||
|
{
|
||||||
|
auto textEdit = p_win->m_editor->getTextEdit();
|
||||||
|
auto localPos = textEdit->cursorRect().bottomRight();
|
||||||
|
if (!textEdit->rect().contains(localPos)) {
|
||||||
|
localPos = QPoint(5, 5);
|
||||||
|
}
|
||||||
|
return textEdit->mapToGlobal(localPos);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <QFocusEvent>
|
#include <QFocusEvent>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
|
#include <QWidgetAction>
|
||||||
|
|
||||||
#include <core/fileopenparameters.h>
|
#include <core/fileopenparameters.h>
|
||||||
#include "toolbarhelper.h"
|
#include "toolbarhelper.h"
|
||||||
@ -33,6 +34,7 @@
|
|||||||
#include "findandreplacewidget.h"
|
#include "findandreplacewidget.h"
|
||||||
#include "editors/statuswidget.h"
|
#include "editors/statuswidget.h"
|
||||||
#include "propertydefs.h"
|
#include "propertydefs.h"
|
||||||
|
#include "floatingwidget.h"
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
@ -865,6 +867,17 @@ void ViewWindow::setupShortcuts()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplySnippet.
|
||||||
|
{
|
||||||
|
auto shortcut = WidgetUtils::createShortcut(editorConfig.getShortcut(EditorConfig::ApplySnippet), this, Qt::WidgetWithChildrenShortcut);
|
||||||
|
if (shortcut) {
|
||||||
|
connect(shortcut, &QShortcut::activated,
|
||||||
|
this, [this]() {
|
||||||
|
applySnippet();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWindow::wheelEvent(QWheelEvent *p_event)
|
void ViewWindow::wheelEvent(QWheelEvent *p_event)
|
||||||
@ -1108,3 +1121,24 @@ void ViewWindow::setWindowFlags(WindowFlags p_flags)
|
|||||||
{
|
{
|
||||||
m_flags = p_flags;
|
m_flags = p_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant ViewWindow::showFloatingWidget(FloatingWidget *p_widget)
|
||||||
|
{
|
||||||
|
// Show the widget through a QWidgetAction in menu.
|
||||||
|
QMenu menu;
|
||||||
|
|
||||||
|
auto act = new QWidgetAction(&menu);
|
||||||
|
// @act will own @p_widget.
|
||||||
|
act->setDefaultWidget(p_widget);
|
||||||
|
menu.addAction(act);
|
||||||
|
|
||||||
|
p_widget->setMenu(&menu);
|
||||||
|
|
||||||
|
menu.exec(getFloatingWidgetPosition());
|
||||||
|
return p_widget->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint ViewWindow::getFloatingWidgetPosition()
|
||||||
|
{
|
||||||
|
return mapToGlobal(QPoint(5, 5));
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@ namespace vnotex
|
|||||||
class EditReadDiscardAction;
|
class EditReadDiscardAction;
|
||||||
class FindAndReplaceWidget;
|
class FindAndReplaceWidget;
|
||||||
class StatusWidget;
|
class StatusWidget;
|
||||||
|
class FloatingWidget;
|
||||||
|
|
||||||
class ViewWindow : public QFrame
|
class ViewWindow : public QFrame
|
||||||
{
|
{
|
||||||
@ -86,6 +87,12 @@ namespace vnotex
|
|||||||
|
|
||||||
virtual void applySnippet(const QString &p_name) = 0;
|
virtual void applySnippet(const QString &p_name) = 0;
|
||||||
|
|
||||||
|
virtual void applySnippet() = 0;
|
||||||
|
|
||||||
|
// Take ownership of @p_widget.
|
||||||
|
// Return the result from the FloatingWidget.
|
||||||
|
QVariant showFloatingWidget(FloatingWidget *p_widget);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void handleEditorConfigChange() = 0;
|
virtual void handleEditorConfigChange() = 0;
|
||||||
|
|
||||||
@ -163,9 +170,6 @@ namespace vnotex
|
|||||||
|
|
||||||
virtual void handleFindAndReplaceWidgetOpened();
|
virtual void handleFindAndReplaceWidgetOpened();
|
||||||
|
|
||||||
// Show message in status widget if exists. Otherwise, show it in the mainwindow's status widget.
|
|
||||||
void showMessage(const QString p_msg);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setCentralWidget(QWidget *p_widget);
|
void setCentralWidget(QWidget *p_widget);
|
||||||
|
|
||||||
@ -228,6 +232,11 @@ namespace vnotex
|
|||||||
|
|
||||||
void read(bool p_save);
|
void read(bool p_save);
|
||||||
|
|
||||||
|
// Show message in status widget if exists. Otherwise, show it in the mainwindow's status widget.
|
||||||
|
void showMessage(const QString p_msg);
|
||||||
|
|
||||||
|
virtual QPoint getFloatingWidgetPosition();
|
||||||
|
|
||||||
static QToolBar *createToolBar(QWidget *p_parent = nullptr);
|
static QToolBar *createToolBar(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
// The revision of the buffer of the last sync content.
|
// The revision of the buffer of the last sync content.
|
||||||
|
@ -47,6 +47,7 @@ SOURCES += \
|
|||||||
$$PWD/filesystemviewer.cpp \
|
$$PWD/filesystemviewer.cpp \
|
||||||
$$PWD/dialogs/folderfilesfilterwidget.cpp \
|
$$PWD/dialogs/folderfilesfilterwidget.cpp \
|
||||||
$$PWD/findandreplacewidget.cpp \
|
$$PWD/findandreplacewidget.cpp \
|
||||||
|
$$PWD/floatingwidget.cpp \
|
||||||
$$PWD/fullscreentoggleaction.cpp \
|
$$PWD/fullscreentoggleaction.cpp \
|
||||||
$$PWD/lineedit.cpp \
|
$$PWD/lineedit.cpp \
|
||||||
$$PWD/lineeditdelegate.cpp \
|
$$PWD/lineeditdelegate.cpp \
|
||||||
@ -62,6 +63,7 @@ SOURCES += \
|
|||||||
$$PWD/outlineprovider.cpp \
|
$$PWD/outlineprovider.cpp \
|
||||||
$$PWD/outlineviewer.cpp \
|
$$PWD/outlineviewer.cpp \
|
||||||
$$PWD/propertydefs.cpp \
|
$$PWD/propertydefs.cpp \
|
||||||
|
$$PWD/quickselector.cpp \
|
||||||
$$PWD/searchinfoprovider.cpp \
|
$$PWD/searchinfoprovider.cpp \
|
||||||
$$PWD/searchpanel.cpp \
|
$$PWD/searchpanel.cpp \
|
||||||
$$PWD/snippetpanel.cpp \
|
$$PWD/snippetpanel.cpp \
|
||||||
@ -151,6 +153,7 @@ HEADERS += \
|
|||||||
$$PWD/filesystemviewer.h \
|
$$PWD/filesystemviewer.h \
|
||||||
$$PWD/dialogs/folderfilesfilterwidget.h \
|
$$PWD/dialogs/folderfilesfilterwidget.h \
|
||||||
$$PWD/findandreplacewidget.h \
|
$$PWD/findandreplacewidget.h \
|
||||||
|
$$PWD/floatingwidget.h \
|
||||||
$$PWD/fullscreentoggleaction.h \
|
$$PWD/fullscreentoggleaction.h \
|
||||||
$$PWD/lineedit.h \
|
$$PWD/lineedit.h \
|
||||||
$$PWD/lineeditdelegate.h \
|
$$PWD/lineeditdelegate.h \
|
||||||
@ -167,6 +170,7 @@ HEADERS += \
|
|||||||
$$PWD/outlineprovider.h \
|
$$PWD/outlineprovider.h \
|
||||||
$$PWD/outlineviewer.h \
|
$$PWD/outlineviewer.h \
|
||||||
$$PWD/propertydefs.h \
|
$$PWD/propertydefs.h \
|
||||||
|
$$PWD/quickselector.h \
|
||||||
$$PWD/searchinfoprovider.h \
|
$$PWD/searchinfoprovider.h \
|
||||||
$$PWD/searchpanel.h \
|
$$PWD/searchpanel.h \
|
||||||
$$PWD/snippetpanel.h \
|
$$PWD/snippetpanel.h \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user