mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
Search: highlight matched items in opened files
This commit is contained in:
parent
8326d3c702
commit
ed8cd503b5
@ -1 +1 @@
|
|||||||
Subproject commit 392c0e218f5981b4fc6566512103b6149f714931
|
Subproject commit 59e53f2cdc2f5a4b9dc44cbf28c483cca07559ba
|
@ -24,7 +24,7 @@
|
|||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
// #define VX_DEBUG_WEB
|
#define VX_DEBUG_WEB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const QString ConfigMgr::c_orgName = "VNote";
|
const QString ConfigMgr::c_orgName = "VNote";
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#ifndef FILEOPENPARAMETERS_H
|
#ifndef FILEOPENPARAMETERS_H
|
||||||
#define FILEOPENPARAMETERS_H
|
#define FILEOPENPARAMETERS_H
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
|
class SearchToken;
|
||||||
|
|
||||||
struct FileOpenParameters
|
struct FileOpenParameters
|
||||||
{
|
{
|
||||||
@ -32,6 +35,9 @@ namespace vnotex
|
|||||||
|
|
||||||
// Whether always open a new window for file.
|
// Whether always open a new window for file.
|
||||||
bool m_alwaysNewWindow = false;
|
bool m_alwaysNewWindow = false;
|
||||||
|
|
||||||
|
// If not empty, use this token to do a search text highlight.
|
||||||
|
QSharedPointer<SearchToken> m_searchToken;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +39,8 @@ new QWebChannel(qt.webChannelTransport,
|
|||||||
window.vnotex.crossCopy(p_id, p_timeStamp, p_target, p_baseUrl, p_html);
|
window.vnotex.crossCopy(p_id, p_timeStamp, p_target, p_baseUrl, p_html);
|
||||||
});
|
});
|
||||||
|
|
||||||
adapter.findTextRequested.connect(function(p_text, p_options) {
|
adapter.findTextRequested.connect(function(p_texts, p_options, p_currentMatchLine) {
|
||||||
window.vnotex.findText(p_text, p_options);
|
window.vnotex.findText(p_texts, p_options, p_currentMatchLine);
|
||||||
});
|
});
|
||||||
|
|
||||||
adapter.contentRequested.connect(function() {
|
adapter.contentRequested.connect(function() {
|
||||||
|
@ -7,6 +7,7 @@ class MarkJs {
|
|||||||
this.markjs = null;
|
this.markjs = null;
|
||||||
this.cache = null;
|
this.cache = null;
|
||||||
this.matchedNodes = null;
|
this.matchedNodes = null;
|
||||||
|
this.currentMatchedNodes = null;
|
||||||
|
|
||||||
this.adapter.on('basicMarkdownRendered', () => {
|
this.adapter.on('basicMarkdownRendered', () => {
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
@ -19,59 +20,102 @@ class MarkJs {
|
|||||||
// wholeWordOnly,
|
// wholeWordOnly,
|
||||||
// regularExpression
|
// regularExpression
|
||||||
// }
|
// }
|
||||||
findText(p_text, p_options) {
|
findText(p_texts, p_options, p_currentMatchLine) {
|
||||||
if (!this.markjs) {
|
if (!this.markjs) {
|
||||||
this.markjs = new Mark(this.container);
|
this.markjs = new Mark(this.container);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p_text) {
|
if (!p_texts || p_texts.length == 0) {
|
||||||
// Clear the cache and highlight.
|
// Clear the cache and highlight.
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.findInCache(p_text, p_options)) {
|
if (this.findInCache(p_texts, p_options, p_currentMatchLine)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A new find.
|
// A new find.
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
|
|
||||||
let callbackFunc = function(markjs, text, options) {
|
let callbackFunc = function(markjs, texts, options, currentMatchLine) {
|
||||||
let _markjs = markjs;
|
let _markjs = markjs;
|
||||||
let _text = text;
|
let _texts = texts;
|
||||||
let _options = options;
|
let _options = options;
|
||||||
return function(totalMatches) {
|
let _currentMatchLine = currentMatchLine;
|
||||||
if (!_markjs.matchedNodes) {
|
return function() {
|
||||||
|
if (_markjs.matchedNodes === null) {
|
||||||
_markjs.matchedNodes = _markjs.container.getElementsByClassName(_markjs.className);
|
_markjs.matchedNodes = _markjs.container.getElementsByClassName(_markjs.className);
|
||||||
|
_markjs.currentMatchedNodes = _markjs.container.getElementsByClassName(_markjs.currentMatchClassName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cache.
|
// Update cache.
|
||||||
_markjs.cache = {
|
_markjs.cache = {
|
||||||
text: _text,
|
texts: _texts,
|
||||||
options: _options,
|
options: _options,
|
||||||
currentIdx: -1
|
currentIdx: -1
|
||||||
}
|
}
|
||||||
|
|
||||||
_markjs.updateCurrentMatch(_text, !_options.findBackward);
|
_markjs.updateCurrentMatch(_texts, !_options.findBackward, _currentMatchLine);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_options.regularExpression) {
|
||||||
|
this.findByOneRegExp({
|
||||||
|
'texts': p_texts,
|
||||||
|
'options': p_options,
|
||||||
|
'textIdx': 0,
|
||||||
|
'lastCallback': callbackFunc(this, p_texts, p_options, p_currentMatchLine)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let opt = this.createMarkjsOptions(p_options);
|
||||||
|
opt.done = callbackFunc(this, p_texts, p_options, p_currentMatchLine);
|
||||||
|
this.markjs.mark(p_texts, opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createMarkjsOptions(p_options) {
|
||||||
let opt = {
|
let opt = {
|
||||||
'element': 'span',
|
'element': 'span',
|
||||||
'className': this.className,
|
'className': this.className,
|
||||||
'caseSensitive': p_options.caseSensitive,
|
'caseSensitive': p_options.caseSensitive,
|
||||||
'accuracy': p_options.wholeWordOnly ? 'exactly' : 'partially',
|
'accuracy': p_options.wholeWordOnly ? 'exactly' : 'partially',
|
||||||
'done': callbackFunc(this, p_text, p_options),
|
|
||||||
// Ignore SVG, or SVG will be corrupted.
|
// Ignore SVG, or SVG will be corrupted.
|
||||||
'exclude': ['svg *']
|
'exclude': ['svg *']
|
||||||
}
|
}
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_options.regularExpression) {
|
// @p_paras: {
|
||||||
// TODO: may need transformation from QRegularExpression to RegExp.
|
// texts,
|
||||||
this.markjs.markRegExp(new RegExp(p_text), opt);
|
// options,
|
||||||
} else {
|
// textIdx,
|
||||||
this.markjs.mark(p_text, opt);
|
// lastCallback
|
||||||
|
// }
|
||||||
|
findByOneRegExp(p_paras) {
|
||||||
|
console.log('findByOneRegExp', p_paras.texts.length, p_paras.textIdx);
|
||||||
|
|
||||||
|
if (p_paras.textIdx >= p_paras.texts.length) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let opt = this.createMarkjsOptions(p_paras.options);
|
||||||
|
if (p_paras.textIdx == p_paras.texts.length - 1) {
|
||||||
|
opt.done = p_paras.lastCallback;
|
||||||
|
} else {
|
||||||
|
let callbackFunc = function(markjs, paras) {
|
||||||
|
let _markjs = markjs;
|
||||||
|
let _paras = paras;
|
||||||
|
return function() {
|
||||||
|
_paras.textIdx += 1;
|
||||||
|
_markjs.findByOneRegExp(_paras);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
opt.done = callbackFunc(this, p_paras);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: may need transformation from QRegularExpression to RegExp.
|
||||||
|
this.markjs.markRegExp(new RegExp(p_paras.texts[p_paras.textIdx]), opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
@ -83,33 +127,62 @@ class MarkJs {
|
|||||||
this.markjs.unmark();
|
this.markjs.unmark();
|
||||||
}
|
}
|
||||||
|
|
||||||
findInCache(p_text, p_options) {
|
findInCache(p_texts, p_options, p_currentMatchLine) {
|
||||||
if (!this.cache) {
|
if (!this.cache) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cache.text === p_text
|
if (p_texts.length != this.cache.texts.length) {
|
||||||
&& this.cache.options.caseSensitive == p_options.caseSensitive
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < p_texts.length; ++i) {
|
||||||
|
if (!(p_texts[i] === this.cache.texts[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cache.options.caseSensitive == p_options.caseSensitive
|
||||||
&& this.cache.options.wholeWordOnly == p_options.wholeWordOnly
|
&& this.cache.options.wholeWordOnly == p_options.wholeWordOnly
|
||||||
&& this.cache.options.regularExpression == p_options.regularExpression) {
|
&& this.cache.options.regularExpression == p_options.regularExpression) {
|
||||||
// Matched. Move current match forward or backward.
|
// Matched. Move current match forward or backward.
|
||||||
this.updateCurrentMatch(p_text, !p_options.findBackward);
|
this.updateCurrentMatch(p_texts, !p_options.findBackward, p_currentMatchLine);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentMatch(p_text, p_forward) {
|
updateCurrentMatch(p_texts, p_forward, p_currentMatchLine) {
|
||||||
let matches = this.matchedNodes.length;
|
let matches = this.matchedNodes.length;
|
||||||
if (matches == 0) {
|
if (matches == 0) {
|
||||||
this.adapter.showFindResult(p_text, 0, 0);
|
this.adapter.showFindResult(p_texts, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.cache.currentIdx >= 0) {
|
|
||||||
|
if (this.currentMatchedNodes.length > 0) {
|
||||||
|
console.assert(this.currentMatchedNodes.length == 1);
|
||||||
|
if (this.cache.currentIdx >= matches
|
||||||
|
|| this.cache.currentIdx < 0
|
||||||
|
|| this.matchedNodes[this.cache.currentIdx] != this.currentMatchedNodes[0]) {
|
||||||
|
// Need to update current index.
|
||||||
|
// The mismatch may comes from the rendering of graphs which may change the matches.
|
||||||
|
for (let i = 0; i < matches; ++i) {
|
||||||
|
if (this.matchedNodes[i] === this.currentMatchedNodes[0]) {
|
||||||
|
this.cache.currentIdx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.matchedNodes[this.cache.currentIdx].classList.remove(this.currentMatchClassName);
|
this.matchedNodes[this.cache.currentIdx].classList.remove(this.currentMatchClassName);
|
||||||
|
} else {
|
||||||
|
this.cache.currentIdx = -1;
|
||||||
}
|
}
|
||||||
if (p_forward) {
|
|
||||||
|
if (p_currentMatchLine > -1) {
|
||||||
|
this.cache.currentIdx = this.binarySearchCurrentIndexForLineNumber(p_currentMatchLine);
|
||||||
|
} else if (p_forward) {
|
||||||
this.cache.currentIdx += 1;
|
this.cache.currentIdx += 1;
|
||||||
if (this.cache.currentIdx >= matches) {
|
if (this.cache.currentIdx >= matches) {
|
||||||
this.cache.currentIdx = 0;
|
this.cache.currentIdx = 0;
|
||||||
@ -120,11 +193,39 @@ class MarkJs {
|
|||||||
this.cache.currentIdx = matches - 1;
|
this.cache.currentIdx = matches - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = this.matchedNodes[this.cache.currentIdx];
|
let node = this.matchedNodes[this.cache.currentIdx];
|
||||||
node.classList.add(this.currentMatchClassName);
|
node.classList.add(this.currentMatchClassName);
|
||||||
if (!Utils.isVisible(node)) {
|
if (!Utils.isVisible(node)) {
|
||||||
node.scrollIntoView();
|
node.scrollIntoView();
|
||||||
}
|
}
|
||||||
this.adapter.showFindResult(p_text, matches, this.cache.currentIdx);
|
this.adapter.showFindResult(p_texts, matches, this.cache.currentIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
binarySearchCurrentIndexForLineNumber(p_lineNumber) {
|
||||||
|
let viewY = this.adapter.nodeLineMapper.getViewYOfLine(p_lineNumber);
|
||||||
|
if (viewY === null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let left = 0;
|
||||||
|
let right = this.matchedNodes.length - 1;
|
||||||
|
let lastIdx = -1;
|
||||||
|
while (left <= right) {
|
||||||
|
let mid = Math.floor((left + right) / 2);
|
||||||
|
let y = this.matchedNodes[mid].getBoundingClientRect().top;
|
||||||
|
if (y >= viewY) {
|
||||||
|
lastIdx = mid;
|
||||||
|
right = mid - 1;
|
||||||
|
} else {
|
||||||
|
left = mid + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastIdx != -1) {
|
||||||
|
return lastIdx;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,22 @@ class NodeLineMapper {
|
|||||||
this.adapter.setHeadings(headings);
|
this.adapter.setHeadings(headings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getViewYOfLine(p_lineNumber) {
|
||||||
|
if (p_lineNumber == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fetchAllNodesWithLineNumber();
|
||||||
|
|
||||||
|
// Binary search the last node with line number not larger than @p_lineNumber.
|
||||||
|
let targetNode = this.binarySearchNodeForLineNumber(this.nodesWithSourceLine, p_lineNumber);
|
||||||
|
if (targetNode) {
|
||||||
|
return targetNode.getBoundingClientRect().top;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scrollToLine(p_lineNumber) {
|
scrollToLine(p_lineNumber) {
|
||||||
if (p_lineNumber == 0) {
|
if (p_lineNumber == 0) {
|
||||||
this.scrollToY(0, false, true);
|
this.scrollToY(0, false, true);
|
||||||
|
@ -280,12 +280,12 @@ class VNoteX extends EventEmitter {
|
|||||||
window.vxMarkdownAdapter.setCrossCopyResult(p_id, p_timeStamp, p_html);
|
window.vxMarkdownAdapter.setCrossCopyResult(p_id, p_timeStamp, p_html);
|
||||||
}
|
}
|
||||||
|
|
||||||
findText(p_text, p_options) {
|
findText(p_texts, p_options, p_currentMatchLine) {
|
||||||
this.searcher.findText(p_text, p_options);
|
this.searcher.findText(p_texts, p_options, p_currentMatchLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
showFindResult(p_text, p_totalMatches, p_currentMatchIndex) {
|
showFindResult(p_texts, p_totalMatches, p_currentMatchIndex) {
|
||||||
window.vxMarkdownAdapter.setFindText(p_text, p_totalMatches, p_currentMatchIndex);
|
window.vxMarkdownAdapter.setFindText(p_texts, p_totalMatches, p_currentMatchIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveContent() {
|
saveContent() {
|
||||||
|
@ -513,3 +513,8 @@ void Searcher::createSearchEngine()
|
|||||||
|
|
||||||
m_engine.reset(new FileSearchEngine());
|
m_engine.reset(new FileSearchEngine());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SearchToken &Searcher::getToken() const
|
||||||
|
{
|
||||||
|
return m_token;
|
||||||
|
}
|
||||||
|
@ -34,6 +34,8 @@ namespace vnotex
|
|||||||
|
|
||||||
SearchState search(const QSharedPointer<SearchOption> &p_option, const QVector<Notebook *> &p_notebooks);
|
SearchState search(const QSharedPointer<SearchOption> &p_option, const QVector<Notebook *> &p_notebooks);
|
||||||
|
|
||||||
|
const SearchToken &getToken() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void progressUpdated(int p_val, int p_maximum);
|
void progressUpdated(int p_val, int p_maximum);
|
||||||
|
|
||||||
|
@ -271,3 +271,21 @@ QString SearchToken::getHelpText()
|
|||||||
// Skip the first line containing the application name.
|
// Skip the first line containing the application name.
|
||||||
return text.mid(text.indexOf('\n') + 1);
|
return text.mid(text.indexOf('\n') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPair<QStringList, FindOptions> SearchToken::toPatterns() const
|
||||||
|
{
|
||||||
|
QPair<QStringList, FindOptions> ret;
|
||||||
|
|
||||||
|
ret.second = m_caseSensitivity == Qt::CaseSensitive ? FindOption::CaseSensitive : FindOption::FindNone;
|
||||||
|
if (m_type == Type::RegularExpression) {
|
||||||
|
ret.second |= FindOption::RegularExpression;
|
||||||
|
|
||||||
|
for (const auto ® : m_regularExpressions) {
|
||||||
|
ret.first << reg.pattern();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret.first = m_keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -54,6 +54,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void endBatchMode();
|
void endBatchMode();
|
||||||
|
|
||||||
|
QPair<QStringList, FindOptions> toPatterns() const;
|
||||||
|
|
||||||
// Compile tokens from keyword.
|
// Compile tokens from keyword.
|
||||||
// Support some magic switchs in the keyword which will suppress the given options.
|
// Support some magic switchs in the keyword which will suppress the given options.
|
||||||
static bool compile(const QString &p_keyword, FindOptions p_options, SearchToken &p_token);
|
static bool compile(const QString &p_keyword, FindOptions p_options, SearchToken &p_token);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
#include <core/global.h>
|
#include <core/global.h>
|
||||||
|
|
||||||
@ -198,8 +199,7 @@ void WidgetUtils::addActionShortcut(QAction *p_action,
|
|||||||
p_action->setText(QString("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText)));
|
p_action->setText(QString("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetUtils::addActionShortcutText(QAction *p_action,
|
void WidgetUtils::addActionShortcutText(QAction *p_action, const QString &p_shortcut)
|
||||||
const QString &p_shortcut)
|
|
||||||
{
|
{
|
||||||
if (p_shortcut.isEmpty()) {
|
if (p_shortcut.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -213,6 +213,20 @@ void WidgetUtils::addActionShortcutText(QAction *p_action,
|
|||||||
p_action->setText(QString("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText)));
|
p_action->setText(QString("%1\t%2").arg(p_action->text(), kseq.toString(QKeySequence::NativeText)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetUtils::addButtonShortcutText(QPushButton *p_button, const QString &p_shortcut)
|
||||||
|
{
|
||||||
|
if (p_shortcut.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence kseq(p_shortcut);
|
||||||
|
if (kseq.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_button->setText(QString("%1 (%2)").arg(p_button->text(), kseq.toString(QKeySequence::NativeText)));
|
||||||
|
}
|
||||||
|
|
||||||
void WidgetUtils::updateSize(QWidget *p_widget)
|
void WidgetUtils::updateSize(QWidget *p_widget)
|
||||||
{
|
{
|
||||||
p_widget->adjustSize();
|
p_widget->adjustSize();
|
||||||
|
@ -19,6 +19,7 @@ class QMenu;
|
|||||||
class QShortcut;
|
class QShortcut;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QLayout;
|
class QLayout;
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
@ -60,8 +61,9 @@ namespace vnotex
|
|||||||
Qt::ShortcutContext p_context = Qt::WindowShortcut);
|
Qt::ShortcutContext p_context = Qt::WindowShortcut);
|
||||||
|
|
||||||
// Just add a shortcut text hint to the action.
|
// Just add a shortcut text hint to the action.
|
||||||
static void addActionShortcutText(QAction *p_action,
|
static void addActionShortcutText(QAction *p_action, const QString &p_shortcut);
|
||||||
const QString &p_shortcut);
|
|
||||||
|
static void addButtonShortcutText(QPushButton *p_button, const QString &p_shortcut);
|
||||||
|
|
||||||
static QShortcut *createShortcut(const QString &p_shortcut,
|
static QShortcut *createShortcut(const QString &p_shortcut,
|
||||||
QWidget *p_widget,
|
QWidget *p_widget,
|
||||||
|
@ -781,12 +781,13 @@ QWidget *ExportDialog::getCustomAdvancedSettings()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto usage = tr("%1: List of input files.\n"
|
auto usage = tr("Command:\n"
|
||||||
"%2: List of paths to search for images and other resources.\n"
|
"\t%1: List of input files.\n"
|
||||||
"%3: Path of rendering CSS style sheet.\n"
|
"\t%2: List of paths to search for images and other resources.\n"
|
||||||
"%4: Path of syntax highlighting CSS style sheet.\n"
|
"\t%3: Path of rendering CSS style sheet.\n"
|
||||||
"%5: Path of output file.\n");
|
"\t%4: Path of syntax highlighting CSS style sheet.\n"
|
||||||
layout->addRow(tr("Command usage:"), new QLabel(usage, widget));
|
"\t%5: Path of output file.\n");
|
||||||
|
layout->addRow(new QLabel(usage, widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -798,7 +799,7 @@ QWidget *ExportDialog::getCustomAdvancedSettings()
|
|||||||
#endif
|
#endif
|
||||||
m_commandTextEdit->setMaximumHeight(m_commandTextEdit->minimumSizeHint().height());
|
m_commandTextEdit->setMaximumHeight(m_commandTextEdit->minimumSizeHint().height());
|
||||||
m_commandTextEdit->setEnabled(false);
|
m_commandTextEdit->setEnabled(false);
|
||||||
layout->addRow(tr("Command:"), m_commandTextEdit);
|
layout->addRow(m_commandTextEdit);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(m_customExportComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
connect(m_customExportComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
|
@ -6,17 +6,10 @@
|
|||||||
#include "../outlineprovider.h"
|
#include "../outlineprovider.h"
|
||||||
#include "plantumlhelper.h"
|
#include "plantumlhelper.h"
|
||||||
#include "graphvizhelper.h"
|
#include "graphvizhelper.h"
|
||||||
|
#include <utils/utils.h>
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
MarkdownViewerAdapter::MarkdownData::MarkdownData(const QString &p_text,
|
|
||||||
int p_lineNumber,
|
|
||||||
const QString &p_anchor)
|
|
||||||
: m_text(p_text),
|
|
||||||
m_position(p_lineNumber, p_anchor)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkdownViewerAdapter::Position::Position(int p_lineNumber, const QString &p_anchor)
|
MarkdownViewerAdapter::Position::Position(int p_lineNumber, const QString &p_anchor)
|
||||||
: m_lineNumber(p_lineNumber),
|
: m_lineNumber(p_lineNumber),
|
||||||
m_anchor(p_anchor)
|
m_anchor(p_anchor)
|
||||||
@ -92,7 +85,10 @@ void MarkdownViewerAdapter::setText(int p_revision,
|
|||||||
emit textUpdated(p_text);
|
emit textUpdated(p_text);
|
||||||
scrollToPosition(Position(p_lineNumber, ""));
|
scrollToPosition(Position(p_lineNumber, ""));
|
||||||
} else {
|
} else {
|
||||||
m_pendingData.reset(new MarkdownData(p_text, p_lineNumber, ""));
|
m_pendingActions.append([this, p_text, p_lineNumber]() {
|
||||||
|
emit textUpdated(p_text);
|
||||||
|
scrollToPosition(Position(p_lineNumber, ""));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +98,9 @@ void MarkdownViewerAdapter::setText(const QString &p_text)
|
|||||||
if (m_viewerReady) {
|
if (m_viewerReady) {
|
||||||
emit textUpdated(p_text);
|
emit textUpdated(p_text);
|
||||||
} else {
|
} else {
|
||||||
m_pendingData.reset(new MarkdownData(p_text, -1, ""));
|
m_pendingActions.append([this, p_text]() {
|
||||||
|
emit textUpdated(p_text);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,15 +112,12 @@ void MarkdownViewerAdapter::setReady(bool p_ready)
|
|||||||
|
|
||||||
m_viewerReady = p_ready;
|
m_viewerReady = p_ready;
|
||||||
if (m_viewerReady) {
|
if (m_viewerReady) {
|
||||||
if (m_pendingData) {
|
for (auto &act : m_pendingActions) {
|
||||||
emit textUpdated(m_pendingData->m_text);
|
act();
|
||||||
scrollToPosition(m_pendingData->m_position);
|
|
||||||
m_pendingData.reset();
|
|
||||||
}
|
}
|
||||||
|
m_pendingActions.clear();
|
||||||
emit viewerReady();
|
emit viewerReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkdownViewerAdapter::scrollToLine(int p_lineNumber)
|
void MarkdownViewerAdapter::scrollToLine(int p_lineNumber)
|
||||||
@ -132,11 +127,9 @@ void MarkdownViewerAdapter::scrollToLine(int p_lineNumber)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_viewerReady) {
|
if (!m_viewerReady) {
|
||||||
if (m_pendingData) {
|
m_pendingActions.append([this, p_lineNumber]() {
|
||||||
m_pendingData->m_position = Position(p_lineNumber, QString());
|
scrollToPosition(Position(p_lineNumber, ""));
|
||||||
} else {
|
});
|
||||||
qWarning() << "Markdown viewer is not ready";
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +314,7 @@ void MarkdownViewerAdapter::setCrossCopyResult(quint64 p_id, quint64 p_timeStamp
|
|||||||
emit crossCopyReady(p_id, p_timeStamp, p_html);
|
emit crossCopyReady(p_id, p_timeStamp, p_html);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkdownViewerAdapter::findText(const QString &p_text, FindOptions p_options)
|
void MarkdownViewerAdapter::findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine)
|
||||||
{
|
{
|
||||||
FindOption opts;
|
FindOption opts;
|
||||||
if (p_options & vnotex::FindOption::FindBackward) {
|
if (p_options & vnotex::FindOption::FindBackward) {
|
||||||
@ -337,12 +330,20 @@ void MarkdownViewerAdapter::findText(const QString &p_text, FindOptions p_option
|
|||||||
opts.m_regularExpression = true;
|
opts.m_regularExpression = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit findTextRequested(p_text, opts.toJson());
|
if (m_viewerReady) {
|
||||||
|
emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
|
||||||
|
} else {
|
||||||
|
m_pendingActions.append([this, p_texts, opts, p_currentMatchLine]() {
|
||||||
|
// FIXME: highlights will be clear once the page is ready. Add a delay here.
|
||||||
|
Utils::sleepWait(1000);
|
||||||
|
emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkdownViewerAdapter::setFindText(const QString &p_text, int p_totalMatches, int p_currentMatchIndex)
|
void MarkdownViewerAdapter::setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex)
|
||||||
{
|
{
|
||||||
emit findTextReady(p_text, p_totalMatches, p_currentMatchIndex);
|
emit findTextReady(p_texts, p_totalMatches, p_currentMatchIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkdownViewerAdapter::setWorkFinished()
|
void MarkdownViewerAdapter::setWorkFinished()
|
||||||
@ -367,7 +368,7 @@ void MarkdownViewerAdapter::reset()
|
|||||||
{
|
{
|
||||||
m_revision = 0;
|
m_revision = 0;
|
||||||
m_viewerReady = false;
|
m_viewerReady = false;
|
||||||
m_pendingData.reset();
|
m_pendingActions.clear();
|
||||||
m_topLineNumber = -1;
|
m_topLineNumber = -1;
|
||||||
m_headings.clear();
|
m_headings.clear();
|
||||||
m_currentHeadingIndex = -1;
|
m_currentHeadingIndex = -1;
|
||||||
|
@ -29,19 +29,6 @@ namespace vnotex
|
|||||||
QString m_anchor;
|
QString m_anchor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MarkdownData
|
|
||||||
{
|
|
||||||
MarkdownData() = default;
|
|
||||||
|
|
||||||
MarkdownData(const QString &p_text,
|
|
||||||
int p_lineNumber,
|
|
||||||
const QString &p_anchor);
|
|
||||||
|
|
||||||
QString m_text;
|
|
||||||
|
|
||||||
Position m_position;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PreviewData
|
struct PreviewData
|
||||||
{
|
{
|
||||||
PreviewData() = default;
|
PreviewData() = default;
|
||||||
@ -119,7 +106,7 @@ namespace vnotex
|
|||||||
|
|
||||||
QString getCrossCopyTargetDisplayName(const QString &p_target) const;
|
QString getCrossCopyTargetDisplayName(const QString &p_target) const;
|
||||||
|
|
||||||
void findText(const QString &p_text, FindOptions p_options);
|
void findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine = -1);
|
||||||
|
|
||||||
void saveContent();
|
void saveContent();
|
||||||
|
|
||||||
@ -168,7 +155,7 @@ namespace vnotex
|
|||||||
|
|
||||||
void setCrossCopyResult(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
|
void setCrossCopyResult(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
|
||||||
|
|
||||||
void setFindText(const QString &p_text, int p_totalMatches, int p_currentMatchIndex);
|
void setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
|
||||||
|
|
||||||
void setSavedContent(const QString &p_headContent, const QString &p_styleContent, const QString &p_content, const QString &p_bodyClassList);
|
void setSavedContent(const QString &p_headContent, const QString &p_styleContent, const QString &p_content, const QString &p_bodyClassList);
|
||||||
|
|
||||||
@ -210,7 +197,7 @@ namespace vnotex
|
|||||||
const QString &p_baseUrl,
|
const QString &p_baseUrl,
|
||||||
const QString &p_html);
|
const QString &p_html);
|
||||||
|
|
||||||
void findTextRequested(const QString &p_text, const QJsonObject &p_options);
|
void findTextRequested(const QStringList &p_texts, const QJsonObject &p_options, int p_currentMatchLine);
|
||||||
|
|
||||||
// Request to get the whole HTML content.
|
// Request to get the whole HTML content.
|
||||||
void contentRequested();
|
void contentRequested();
|
||||||
@ -243,7 +230,7 @@ namespace vnotex
|
|||||||
|
|
||||||
void crossCopyReady(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
|
void crossCopyReady(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
|
||||||
|
|
||||||
void findTextReady(const QString &p_text, int p_totalMatches, int p_currentMatchIndex);
|
void findTextReady(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
|
||||||
|
|
||||||
void contentReady(const QString &p_headContent,
|
void contentReady(const QString &p_headContent,
|
||||||
const QString &p_styleContent,
|
const QString &p_styleContent,
|
||||||
@ -260,8 +247,8 @@ namespace vnotex
|
|||||||
// Whether web side viewer is ready to handle text update.
|
// Whether web side viewer is ready to handle text update.
|
||||||
bool m_viewerReady = false;
|
bool m_viewerReady = false;
|
||||||
|
|
||||||
// Pending Markdown data for the viewer once it is ready.
|
// Pending actions for the viewer once it is ready.
|
||||||
QScopedPointer<MarkdownData> m_pendingData;
|
QVector<std::function<void()>> m_pendingActions;
|
||||||
|
|
||||||
// Source line number of the top element node at web side.
|
// Source line number of the top element node at web side.
|
||||||
int m_topLineNumber = -1;
|
int m_topLineNumber = -1;
|
||||||
|
@ -14,11 +14,13 @@
|
|||||||
#include "lineedit.h"
|
#include "lineedit.h"
|
||||||
#include "widgetsfactory.h"
|
#include "widgetsfactory.h"
|
||||||
#include <utils/iconutils.h>
|
#include <utils/iconutils.h>
|
||||||
|
#include <utils/widgetutils.h>
|
||||||
#include <core/thememgr.h>
|
#include <core/thememgr.h>
|
||||||
#include <core/vnotex.h>
|
#include <core/vnotex.h>
|
||||||
#include "propertydefs.h"
|
#include "propertydefs.h"
|
||||||
#include "configmgr.h"
|
#include <core/configmgr.h>
|
||||||
#include "widgetconfig.h"
|
#include <core/editorconfig.h>
|
||||||
|
#include <widgetconfig.h>
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
@ -80,12 +82,16 @@ void FindAndReplaceWidget::setupUI()
|
|||||||
|
|
||||||
setFocusProxy(m_findLineEdit);
|
setFocusProxy(m_findLineEdit);
|
||||||
|
|
||||||
|
const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
|
||||||
|
|
||||||
auto findNextBtn = new QPushButton(tr("Find &Next"), this);
|
auto findNextBtn = new QPushButton(tr("Find &Next"), this);
|
||||||
|
WidgetUtils::addButtonShortcutText(findNextBtn, editorConfig.getShortcut(EditorConfig::FindNext));
|
||||||
findNextBtn->setDefault(true);
|
findNextBtn->setDefault(true);
|
||||||
connect(findNextBtn, &QPushButton::clicked,
|
connect(findNextBtn, &QPushButton::clicked,
|
||||||
this, &FindAndReplaceWidget::findNext);
|
this, &FindAndReplaceWidget::findNext);
|
||||||
|
|
||||||
auto findPrevBtn = new QPushButton(tr("Find &Previous"), this);
|
auto findPrevBtn = new QPushButton(tr("Find &Previous"), this);
|
||||||
|
WidgetUtils::addButtonShortcutText(findPrevBtn, editorConfig.getShortcut(EditorConfig::FindPrevious));
|
||||||
connect(findPrevBtn, &QPushButton::clicked,
|
connect(findPrevBtn, &QPushButton::clicked,
|
||||||
this, &FindAndReplaceWidget::findPrevious);
|
this, &FindAndReplaceWidget::findPrevious);
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ void HistoryPanel::updateHistoryList()
|
|||||||
|
|
||||||
if (itemIdx >= 0) {
|
if (itemIdx >= 0) {
|
||||||
// Older.
|
// Older.
|
||||||
auto sepItem = ListWidget::createSeparatorItem(tr(">>> Older"));
|
auto sepItem = ListWidget::createSeparatorItem(tr("Older"));
|
||||||
m_historyList->addItem(sepItem);
|
m_historyList->addItem(sepItem);
|
||||||
|
|
||||||
for (; itemIdx >= 0; --itemIdx) {
|
for (; itemIdx >= 0; --itemIdx) {
|
||||||
@ -191,11 +191,11 @@ void HistoryPanel::updateSeparators()
|
|||||||
auto curDateTime = QDateTime::currentDateTime();
|
auto curDateTime = QDateTime::currentDateTime();
|
||||||
curDateTime.setTime(QTime());
|
curDateTime.setTime(QTime());
|
||||||
|
|
||||||
m_separators[0].m_text = tr(">>> Today");
|
m_separators[0].m_text = tr("Today");
|
||||||
m_separators[0].m_dateUtc = curDateTime.toUTC();
|
m_separators[0].m_dateUtc = curDateTime.toUTC();
|
||||||
m_separators[1].m_text = tr(">>> Yesterday");
|
m_separators[1].m_text = tr("Yesterday");
|
||||||
m_separators[1].m_dateUtc = curDateTime.addDays(-1).toUTC();
|
m_separators[1].m_dateUtc = curDateTime.addDays(-1).toUTC();
|
||||||
m_separators[2].m_text = tr(">>> Last 7 Days");
|
m_separators[2].m_text = tr("Last 7 Days");
|
||||||
m_separators[2].m_dateUtc = curDateTime.addDays(-7).toUTC();
|
m_separators[2].m_dateUtc = curDateTime.addDays(-7).toUTC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,8 +457,8 @@ void MarkdownViewWindow::setupViewer()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(adapter, &MarkdownViewerAdapter::findTextReady,
|
connect(adapter, &MarkdownViewerAdapter::findTextReady,
|
||||||
this, [this](const QString &p_text, int p_totalMatches, int p_currentMatchIndex) {
|
this, [this](const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex) {
|
||||||
this->showFindResult(p_text, p_totalMatches, p_currentMatchIndex);
|
this->showFindResult(p_texts, p_totalMatches, p_currentMatchIndex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,19 +944,19 @@ void MarkdownViewWindow::handleFindTextChanged(const QString &p_text, FindOption
|
|||||||
{
|
{
|
||||||
if (isReadMode()) {
|
if (isReadMode()) {
|
||||||
if (p_options & FindOption::IncrementalSearch) {
|
if (p_options & FindOption::IncrementalSearch) {
|
||||||
adapter()->findText(p_text, p_options);
|
adapter()->findText(QStringList(p_text), p_options);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TextViewWindowHelper::handleFindTextChanged(this, p_text, p_options);
|
TextViewWindowHelper::handleFindTextChanged(this, p_text, p_options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkdownViewWindow::handleFindNext(const QString &p_text, FindOptions p_options)
|
void MarkdownViewWindow::handleFindNext(const QStringList &p_texts, FindOptions p_options)
|
||||||
{
|
{
|
||||||
if (isReadMode()) {
|
if (isReadMode()) {
|
||||||
adapter()->findText(p_text, p_options);
|
adapter()->findText(p_texts, p_options);
|
||||||
} else {
|
} else {
|
||||||
TextViewWindowHelper::handleFindNext(this, p_text, p_options);
|
TextViewWindowHelper::handleFindNext(this, p_texts, p_options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -983,7 +983,7 @@ void MarkdownViewWindow::handleFindAndReplaceWidgetClosed()
|
|||||||
if (m_editor) {
|
if (m_editor) {
|
||||||
TextViewWindowHelper::handleFindAndReplaceWidgetClosed(this);
|
TextViewWindowHelper::handleFindAndReplaceWidgetClosed(this);
|
||||||
} else {
|
} else {
|
||||||
adapter()->findText("", FindOption::FindNone);
|
adapter()->findText(QStringList(), FindOption::FindNone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,6 +1013,10 @@ void MarkdownViewWindow::handleFileOpenParameters(const QSharedPointer<FileOpenP
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollToLine(p_paras->m_lineNumber);
|
scrollToLine(p_paras->m_lineNumber);
|
||||||
|
|
||||||
|
if (p_paras->m_searchToken) {
|
||||||
|
findTextBySearchToken(p_paras->m_searchToken, p_paras->m_lineNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,6 +1035,19 @@ void MarkdownViewWindow::scrollToLine(int p_lineNumber)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkdownViewWindow::findTextBySearchToken(const QSharedPointer<SearchToken> &p_token, int p_currentMatchLine)
|
||||||
|
{
|
||||||
|
if (isReadMode()) {
|
||||||
|
Q_ASSERT(m_viewer);
|
||||||
|
const auto patterns = p_token->toPatterns();
|
||||||
|
updateLastFindInfo(patterns.first, patterns.second);
|
||||||
|
adapter()->findText(patterns.first, patterns.second, p_currentMatchLine);
|
||||||
|
} else {
|
||||||
|
Q_ASSERT(m_editor);
|
||||||
|
TextViewWindowHelper::findTextBySearchToken(this, p_token, p_currentMatchLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MarkdownViewWindow::isReadMode() const
|
bool MarkdownViewWindow::isReadMode() const
|
||||||
{
|
{
|
||||||
return m_mode == ViewWindowMode::Read;
|
return m_mode == ViewWindowMode::Read;
|
||||||
|
@ -24,6 +24,7 @@ namespace vnotex
|
|||||||
class MarkdownEditorConfig;
|
class MarkdownEditorConfig;
|
||||||
class EditorConfig;
|
class EditorConfig;
|
||||||
class ImageHost;
|
class ImageHost;
|
||||||
|
class SearchToken;
|
||||||
|
|
||||||
class MarkdownViewWindow : public ViewWindow
|
class MarkdownViewWindow : public ViewWindow
|
||||||
{
|
{
|
||||||
@ -65,7 +66,7 @@ namespace vnotex
|
|||||||
|
|
||||||
void handleFindTextChanged(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
|
void handleFindTextChanged(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
void handleFindNext(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
|
void handleFindNext(const QStringList &p_texts, FindOptions p_options) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
|
void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@ -146,6 +147,8 @@ namespace vnotex
|
|||||||
|
|
||||||
void scrollToLine(int p_lineNumber);
|
void scrollToLine(int p_lineNumber);
|
||||||
|
|
||||||
|
void findTextBySearchToken(const QSharedPointer<SearchToken> &p_token, int p_currentMatchLine);
|
||||||
|
|
||||||
bool isReadMode() const;
|
bool isReadMode() const;
|
||||||
|
|
||||||
void updatePreviewHelperFromConfig(const MarkdownEditorConfig &p_config);
|
void updatePreviewHelperFromConfig(const MarkdownEditorConfig &p_config);
|
||||||
|
@ -554,6 +554,9 @@ void SearchPanel::prepareLocationList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_locationList->clear();
|
m_locationList->clear();
|
||||||
|
|
||||||
|
m_searchTokenOfSession.clear();
|
||||||
|
|
||||||
m_locationList->startSession([this](const Location &p_location) {
|
m_locationList->startSession([this](const Location &p_location) {
|
||||||
handleLocationActivated(p_location);
|
handleLocationActivated(p_location);
|
||||||
});
|
});
|
||||||
@ -561,9 +564,15 @@ void SearchPanel::prepareLocationList()
|
|||||||
|
|
||||||
void SearchPanel::handleLocationActivated(const Location &p_location)
|
void SearchPanel::handleLocationActivated(const Location &p_location)
|
||||||
{
|
{
|
||||||
qDebug() << "location activated" << p_location;
|
Q_ASSERT(m_searcher);
|
||||||
|
|
||||||
|
if (!m_searchTokenOfSession) {
|
||||||
|
m_searchTokenOfSession = QSharedPointer<SearchToken>::create(m_searcher->getToken());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: decode the path of location and handle different types of destination.
|
// TODO: decode the path of location and handle different types of destination.
|
||||||
auto paras = QSharedPointer<FileOpenParameters>::create();
|
auto paras = QSharedPointer<FileOpenParameters>::create();
|
||||||
paras->m_lineNumber = p_location.m_lineNumber;
|
paras->m_lineNumber = p_location.m_lineNumber;
|
||||||
|
paras->m_searchToken = m_searchTokenOfSession;
|
||||||
emit VNoteX::getInst().openFileRequested(p_location.m_path, paras);
|
emit VNoteX::getInst().openFileRequested(p_location.m_path, paras);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ namespace vnotex
|
|||||||
class Notebook;
|
class Notebook;
|
||||||
class LocationList;
|
class LocationList;
|
||||||
struct Location;
|
struct Location;
|
||||||
|
class SearchToken;
|
||||||
|
|
||||||
class ISearchInfoProvider
|
class ISearchInfoProvider
|
||||||
{
|
{
|
||||||
@ -145,6 +146,8 @@ namespace vnotex
|
|||||||
Searcher *m_searcher = nullptr;
|
Searcher *m_searcher = nullptr;
|
||||||
|
|
||||||
LocationList *m_locationList = nullptr;
|
LocationList *m_locationList = nullptr;
|
||||||
|
|
||||||
|
QSharedPointer<SearchToken> m_searchTokenOfSession;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,9 +218,9 @@ void TextViewWindow::handleFindTextChanged(const QString &p_text, FindOptions p_
|
|||||||
TextViewWindowHelper::handleFindTextChanged(this, p_text, p_options);
|
TextViewWindowHelper::handleFindTextChanged(this, p_text, p_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextViewWindow::handleFindNext(const QString &p_text, FindOptions p_options)
|
void TextViewWindow::handleFindNext(const QStringList &p_texts, FindOptions p_options)
|
||||||
{
|
{
|
||||||
TextViewWindowHelper::handleFindNext(this, p_text, p_options);
|
TextViewWindowHelper::handleFindNext(this, p_texts, p_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextViewWindow::handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
|
void TextViewWindow::handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
|
||||||
@ -261,6 +261,10 @@ void TextViewWindow::handleFileOpenParameters(const QSharedPointer<FileOpenParam
|
|||||||
if (p_paras->m_lineNumber > -1) {
|
if (p_paras->m_lineNumber > -1) {
|
||||||
m_editor->scrollToLine(p_paras->m_lineNumber, true);
|
m_editor->scrollToLine(p_paras->m_lineNumber, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_paras->m_searchToken) {
|
||||||
|
TextViewWindowHelper::findTextBySearchToken(this, p_paras->m_searchToken, p_paras->m_lineNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewWindowSession TextViewWindow::saveSession() const
|
ViewWindowSession TextViewWindow::saveSession() const
|
||||||
|
@ -45,7 +45,7 @@ namespace vnotex
|
|||||||
|
|
||||||
void handleFindTextChanged(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
|
void handleFindTextChanged(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
void handleFindNext(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
|
void handleFindNext(const QStringList &p_texts, FindOptions p_options) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
|
void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QTextBlock>
|
#include <QTextBlock>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
#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 <snippet/snippetmgr.h>
|
||||||
|
#include <search/searchtoken.h>
|
||||||
|
|
||||||
#include "quickselector.h"
|
#include "quickselector.h"
|
||||||
|
|
||||||
@ -169,10 +171,10 @@ namespace vnotex
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename _ViewWindow>
|
template <typename _ViewWindow>
|
||||||
static void handleFindNext(_ViewWindow *p_win, const QString &p_text, FindOptions p_options)
|
static void handleFindNext(_ViewWindow *p_win, const QStringList &p_texts, FindOptions p_options)
|
||||||
{
|
{
|
||||||
const auto result = p_win->m_editor->findText(p_text, toEditorFindFlags(p_options));
|
const auto result = p_win->m_editor->findText(p_texts, toEditorFindFlags(p_options));
|
||||||
p_win->showFindResult(p_text, result.m_totalMatches, result.m_currentMatchIndex);
|
p_win->showFindResult(p_texts, result.m_totalMatches, result.m_currentMatchIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename _ViewWindow>
|
template <typename _ViewWindow>
|
||||||
@ -293,6 +295,15 @@ namespace vnotex
|
|||||||
}
|
}
|
||||||
return textEdit->mapToGlobal(localPos);
|
return textEdit->mapToGlobal(localPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename _ViewWindow>
|
||||||
|
static void findTextBySearchToken(_ViewWindow *p_win, const QSharedPointer<SearchToken> &p_token, int p_currentMatchLine)
|
||||||
|
{
|
||||||
|
const auto patterns = p_token->toPatterns();
|
||||||
|
p_win->updateLastFindInfo(patterns.first, patterns.second);
|
||||||
|
const auto result = p_win->m_editor->findText(patterns.first, toEditorFindFlags(patterns.second), 0, -1, p_currentMatchLine);
|
||||||
|
p_win->showFindResult(patterns.first, result.m_totalMatches, result.m_currentMatchIndex);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,9 +1007,9 @@ void ViewWindow::handleFindTextChanged(const QString &p_text, FindOptions p_opti
|
|||||||
Q_UNUSED(p_options);
|
Q_UNUSED(p_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWindow::handleFindNext(const QString &p_text, FindOptions p_options)
|
void ViewWindow::handleFindNext(const QStringList &p_texts, FindOptions p_options)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p_text);
|
Q_UNUSED(p_texts);
|
||||||
Q_UNUSED(p_options);
|
Q_UNUSED(p_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1039,46 +1039,49 @@ void ViewWindow::findNextOnLastFind(bool p_forward)
|
|||||||
{
|
{
|
||||||
// Check if need to update the find info.
|
// Check if need to update the find info.
|
||||||
if (m_findAndReplace && m_findAndReplace->isVisible()) {
|
if (m_findAndReplace && m_findAndReplace->isVisible()) {
|
||||||
m_findInfo.m_text = m_findAndReplace->getFindText();
|
m_findInfo.m_texts = QStringList(m_findAndReplace->getFindText());
|
||||||
m_findInfo.m_options = m_findAndReplace->getOptions();
|
m_findInfo.m_options = m_findAndReplace->getOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_findInfo.m_text.isEmpty()) {
|
if (m_findInfo.m_texts.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_forward) {
|
if (p_forward) {
|
||||||
handleFindNext(m_findInfo.m_text, m_findInfo.m_options & ~FindOption::FindBackward);
|
handleFindNext(m_findInfo.m_texts, m_findInfo.m_options & ~FindOption::FindBackward);
|
||||||
} else {
|
} else {
|
||||||
handleFindNext(m_findInfo.m_text, m_findInfo.m_options | FindOption::FindBackward);
|
handleFindNext(m_findInfo.m_texts, m_findInfo.m_options | FindOption::FindBackward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWindow::findNext(const QString &p_text, FindOptions p_options)
|
void ViewWindow::findNext(const QString &p_text, FindOptions p_options)
|
||||||
{
|
{
|
||||||
m_findInfo.m_text = p_text;
|
const QStringList texts(p_text);
|
||||||
|
|
||||||
|
m_findInfo.m_texts = texts;
|
||||||
m_findInfo.m_options = p_options;
|
m_findInfo.m_options = p_options;
|
||||||
handleFindNext(p_text, p_options);
|
handleFindNext(texts, p_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWindow::replace(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
|
void ViewWindow::replace(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
|
||||||
{
|
{
|
||||||
m_findInfo.m_text = p_text;
|
m_findInfo.m_texts = QStringList(p_text);
|
||||||
m_findInfo.m_options = p_options;
|
m_findInfo.m_options = p_options;
|
||||||
handleReplace(p_text, p_options, p_replaceText);
|
handleReplace(p_text, p_options, p_replaceText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWindow::replaceAll(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
|
void ViewWindow::replaceAll(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
|
||||||
{
|
{
|
||||||
m_findInfo.m_text = p_text;
|
m_findInfo.m_texts = QStringList(p_text);
|
||||||
m_findInfo.m_options = p_options;
|
m_findInfo.m_options = p_options;
|
||||||
handleReplaceAll(p_text, p_options, p_replaceText);
|
handleReplaceAll(p_text, p_options, p_replaceText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewWindow::showFindResult(const QString &p_text, int p_totalMatches, int p_currentMatchIndex)
|
void ViewWindow::showFindResult(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex)
|
||||||
{
|
{
|
||||||
if (p_totalMatches == 0) {
|
if (p_totalMatches == 0) {
|
||||||
showMessage(tr("Pattern not found: %1").arg(p_text));
|
showMessage(tr("Pattern not found: %1%2").arg(p_texts.isEmpty() ? QString() : p_texts[0],
|
||||||
|
p_texts.size() > 1 ? tr(" [+]"): QString()));
|
||||||
} else {
|
} else {
|
||||||
showMessage(tr("Match found: %1/%2").arg(p_currentMatchIndex + 1).arg(p_totalMatches));
|
showMessage(tr("Match found: %1/%2").arg(p_currentMatchIndex + 1).arg(p_totalMatches));
|
||||||
}
|
}
|
||||||
@ -1215,3 +1218,9 @@ void ViewWindow::updateImageHostMenu()
|
|||||||
|
|
||||||
handleImageHostChanged(curHost ? curHost->getName() : nullptr);
|
handleImageHostChanged(curHost ? curHost->getName() : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewWindow::updateLastFindInfo(const QStringList &p_texts, FindOptions p_options)
|
||||||
|
{
|
||||||
|
m_findInfo.m_texts = p_texts;
|
||||||
|
m_findInfo.m_options = p_options;
|
||||||
|
}
|
||||||
|
@ -164,7 +164,7 @@ namespace vnotex
|
|||||||
|
|
||||||
virtual void handleFindTextChanged(const QString &p_text, FindOptions p_options);
|
virtual void handleFindTextChanged(const QString &p_text, FindOptions p_options);
|
||||||
|
|
||||||
virtual void handleFindNext(const QString &p_text, FindOptions p_options);
|
virtual void handleFindNext(const QStringList &p_texts, FindOptions p_options);
|
||||||
|
|
||||||
virtual void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText);
|
virtual void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText);
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ namespace vnotex
|
|||||||
bool findAndReplaceWidgetVisible() const;
|
bool findAndReplaceWidgetVisible() const;
|
||||||
|
|
||||||
// @p_currentMatchIndex: 0-based.
|
// @p_currentMatchIndex: 0-based.
|
||||||
void showFindResult(const QString &p_text, int p_totalMatches, int p_currentMatchIndex);
|
void showFindResult(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
|
||||||
|
|
||||||
void showReplaceResult(const QString &p_text, int p_totalReplaces);
|
void showReplaceResult(const QString &p_text, int p_totalReplaces);
|
||||||
|
|
||||||
@ -240,6 +240,8 @@ namespace vnotex
|
|||||||
// Show message in status widget if exists. Otherwise, show it in the mainwindow's status widget.
|
// Show message in status widget if exists. Otherwise, show it in the mainwindow's status widget.
|
||||||
void showMessage(const QString p_msg);
|
void showMessage(const QString p_msg);
|
||||||
|
|
||||||
|
void updateLastFindInfo(const QStringList &p_texts, FindOptions p_options);
|
||||||
|
|
||||||
virtual QPoint getFloatingWidgetPosition();
|
virtual QPoint getFloatingWidgetPosition();
|
||||||
|
|
||||||
static QToolBar *createToolBar(QWidget *p_parent = nullptr);
|
static QToolBar *createToolBar(QWidget *p_parent = nullptr);
|
||||||
@ -259,7 +261,7 @@ namespace vnotex
|
|||||||
private:
|
private:
|
||||||
struct FindInfo
|
struct FindInfo
|
||||||
{
|
{
|
||||||
QString m_text;
|
QStringList m_texts;
|
||||||
FindOptions m_options;
|
FindOptions m_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user